2010-01-26 4 views
6

У нас есть ArrayList элементов в нескольких классах, которые приносят мне проблемы каждый раз, когда я хотел бы вставить новый элемент в список. С моей стороны было ошибкой разрабатывать классы так, как я делал, но изменение дизайна теперь было бы скорее головной болью, чем это стоит (бюрократическая модель водопада). Я должен был предвидеть изменения формата в документах, которые клиент поставлял нам водопад будь проклят.Код переформатирования с регулярными выражениями

Я хотел бы написать простой скрипт в python, который входит в класс, добавляет элемент в список и затем увеличивает все результаты поиска для следующих элементов. Это не звучит очень толковый:

Foo extends Bar{ 
    public Foo(){ 
     m_Tags.add("Jane"); 
     m_Tags.add("Bob"); 
     m_Tags.add("Jim"); 
    } 

    public String GetJane() { return m_ParsedValue.get(m_Tags.get(1)); } 
    public String GetBob() { return m_ParsedValue.get(m_Tags.get(2)); } 
    public String GetJim() { return m_ParsedValue.get(m_Tags.get(3)); } 
} 

Вы видите, если я хочу, чтобы добавить значение между «Джейн» и «Боб» Я тогда придется увеличивать целые числа в Get * функций. Я просто хочу написать простой скрипт в Python, который выполняет эту работу для меня. Кто-то, кого я очень уважаю, предлагал regex.

Edit:

Да, LinkedHashMap. Так просто, так просто и так не в дизайне сейчас. Я ненавижу водопад. Ненавижу это со страстью. Весь этот бит был «небольшой» и «легкой» частью, которая «не должна тратить много времени на разработку». Я сделал ошибки. Теперь он застрял в камне.

+4

Позволь мне получить это прямо: у вас есть огромная, неуправляемая масса коды Java, наполненная магия номера и жестко закодированные строки, и вы хотите вставить их в середину и увеличивать следующие числа с помощью python? – Jorenko

+0

Почему вы не используете HashMap для этого? Просто используйте строку в качестве ключа и верните номер, который вы хотите ... Мне кажется, что это более естественный способ сделать это. – Khelben

+0

@ Джоренко: Да и нет.Строки берутся из проприетарных отформатированных клиентских документов, которые передаются в нашу заявку. Код не огромен и не нарушает DRY. Однако вы правы. Там тонна волшебных чисел, и да, я хочу вставить один посередине. – wheaties

ответ

4

Вы хотите, чтобы ваше регулярное выражение было таким же гибким, как и компилятор, в отношении пробелов между токенами. Выполнение этого и подражание использованию пробелов делает шаблон довольно грязным. Код ниже (извините: Perl, а не Python) редактирует исходные файлы на месте.

#! /usr/bin/perl -i.bak  
use warnings; 
use strict; 
my $template = 
    '^(public 
     String 
     Get)(\w+)(\(\) { return 
     m_ParsedValue . get \(m_Tags . get \()(\d+)(\) \) ; })$'; 
$template =~ s/ +/\\s*/g; 
$template =~ s/(\r?\n)+/\\s+/g; 
my $getter = qr/$template/x; 

die "Usage: $0 after new-name source ..\n" unless @ARGV >= 3; 
my $after = shift; 
my $add = shift; 
my $index; 
while (<>) { 
    unless (/$getter/) { 
    print; 
    next; 
    } 
    my($abc,$name,$lmno,$i,$xyz) = ($1,$2,$3,$4,$5); 
    if (defined $index) { 
    print join "" => $abc, $name, $lmno, ++$index, $xyz; 
    } 
    else { 
    if ($name eq $after) { 
     $index = $i; 
     print; print join "" => $abc, $add, $lmno, ++$index, $xyz; 
    } 
    else { print; } 
    } 
} 

Например,

$ ./add-after Jane Foo code.java 
$ cat code.java 
Foo extends Bar{ 
    public Foo(){ 
     m_Tags.add("Jane"); 
     m_Tags.add("Bob"); 
     m_Tags.add("Jim"); 
    } 

    public String GetJane() { return m_ParsedValue.get(m_Tags.get(1)); } 
    public String GetFoo() { return m_ParsedValue.get(m_Tags.get(2)); } 
    public String GetBob() { return m_ParsedValue.get(m_Tags.get(3)); } 
    public String GetJim() { return m_ParsedValue.get(m_Tags.get(4)); } 
}
+0

спасибо. Я могу показать это кому-то, кто знает perl и python. Они смогут мне помочь. – wheaties

+0

Добро пожаловать. Я рад, что это помогает. –

4

Не делайте этого с регулярным выражением. Создавайте символические константы (используя, например, перечисление), которые отображают имена в числа.

+0

Технически, если бы мне пришлось перепроектировать с самого начала, я бы сделал именованную переменную для каждого компонента, присвоенную ей списку, а затем передал этот список функциям синтаксического анализа. Тогда мне не нужно было бы справляться со всеми этими магическими цифрами. – wheaties

+0

Вам не нужен редизайн. Просто добавьте константы. Затем используйте скрипт, если вы должны его использовать, увеличьте константы. – vy32

0

Я делаю это (ну, что-то очень похожее) прямо сейчас, но используя макросы Excel и VBA. Все бизнес-ценности организованы и заказываются в электронной таблице. Мне просто нужно нажать кнопку, чтобы создать соответствующий код для выбранных ячеек, а затем скопировать-вставить в среду IDE. Еще лучше, у меня есть несколько «столбцов кода» для каждой строки. Некоторые из них генерируют запросы, некоторые преобразования XSL и некоторые процедуры. Для одной строки бизнес-данных я могу легко получить все три типа сгенерированного кода.

Я нашел это (сгенерировать), чтобы быть намного проще, чем переформатировать существующий код, который у меня был.

+0

Это звучит как кошмар системы. –

+0

@matt b: Сначала я тоже так подумал. Аналитики поддерживают бизнес-данные в электронных таблицах (они на самом деле довольно хорошо организованы), поэтому я могу легко взять их копию, а затем применить свои макросы, чтобы получить много кодовых табличек, которые редко нуждаются в ручной настройке. Это очень быстро для разработки и соответствует ТОЧНО с бизнес-требованиями - это также помогает найти ошибки в требованиях. – FrustratedWithFormsDesigner

4

Комментарии о бэд-практик, кроме - вот это код, который вы просили в языке, который вы просили. Лучше всего, если вы поддерживаете систему таким образом, вероятно, было бы, чтобы эти java-файлы были автоматически сгенерированы в самом процессе сборки - вы просто сохраните список имен в файле .txt в каталоге. Этот сценарий подходит для этого.

(Это не будет изменять ваши файлы, это genrate новых на основе шаблона, публикуемыми здесь)

import re, sys 

template = """Foo extends Bar{ 
    public Foo(){ 
%s 
    } 

%s 
} 
""" 

tag_templ = """  m_Tags.add("%s");""" 
getter_templ = """ public String GetJane() { return m_ParsedValue.get(m_Tags.get(%d)); }""" 

def parse_names(filename): 
    data = open(filename).read() 
    names = re.findall(r'm_Tags\.add\("(.*?)"', data) 
    return names 

def create_file(filename, names): 
    tag_lines = [tag_templ % name for name in names] 
    getter_lines = [getter_templ % (i + 1) for i in range(len(names))] 
    code = template % ("\n".join(tag_lines), "\n".join(getter_lines)) 
    file = open(filename,"wt") 
    file.write(code) 
    file.close() 

def insert_name(after, new_name, names): 
    names.insert(names.index(after) + 1, new_name) 

if __name__ == "__main__": 
    if len(sys.argv) < 4: 
     sys.stderr.write("Usage: changer.py <filename> <name-before-insertion> <new-name>") 
     sys.exit(1) 
    filename, name_before, new_name = sys.argv[1:] 
    names = parse_names(filename) 
    insert_name(name_before, new_name, names) 
    create_file(filename, names) 
+0

Спасибо за это и спасибо, что не комментировали мои ошибки. Это действительно отличная идея. Я пытаюсь перейти к более прагматичному подходу (только что закончил прагматичный программист месяц назад.) – wheaties

+0

Шаблон - это абсолютно правильный путь. Но почему бы не сделать это еще дальше и использовать настоящую библиотеку шаблонов, такую ​​как Template Toolkit для Python? http://tt2.org/python/index.html – daotoad

+0

Becasue tehre не нужно делать это на таком простом примере? Один из мотивов Python - «просто лучше, чем сложный» - и даже для реального кода в стандартном libs есть достаточно подходящие методы форматирования шаблонов, чтобы оправдывать внешние зависимости для такого простого случая. – jsbueno