2008-08-29 6 views
8

Я работаю над базой кода C++, которая была недавно перенесена из X/Motif в Qt. Я пытаюсь написать Perl-скрипт, который заменит все вхождения Boolean (из X) на bool. Сценарий просто выполняет простую замену.Regex заменить Boolean на bool

s/\bBoolean\b/bool/g 

Есть несколько условий.

1) У нас есть CORBA в нашем коде и \ b соответствует CORBA :: Boolean, который должен быть изменен не.
2) Это не должно совпадать, если он был найден в виде строки (т.е. "Boolean")

Обновлено:

Для # 1, я использовал просмотра назад

s/(?<!:)\bBoolean\b/bool/g; 

Для # 2 , Я использовал lookahead.

s/(?<!:)\bBoolean\b(?!")/bool/g</pre> 

Это, скорее всего, будет работать для моей ситуации, но как насчет следующих улучшений?

3) Не совпадают, если в середине строки (спасибо nohat).
4) Не совпадают, если в комментарии. (// или/** /)

+0

примечание стороны: http://stackoverflow.com/questions/72312/how-should-i-capitalize-perl#72757 – szabgab 2008-09-17 05:13:51

ответ

0

Чтобы исправить условие 1 попробовать:

s/[^:]\bBoolean\b(?!")/bool/g 

[^:] говорит, чтобы соответствовать любому символу, кроме ":".

1
s/[^:]\bBoolean\b[^"]/bool/g 

Редактировать: Крысы, снова избили. +1 за избиение меня, добрый сэр.

3

s/[^:] \ bBoolean \ б/BOOL/г

Это не соответствует строки, где Булева находится в том, что начало линии becuase [^ ("?!): ] является «совпадением с символом, который не является:».

2

Остерегайтесь этого утверждения, которое соответствует совпадению, если Boolean - это последняя часть строки, но не в середине string. Вам нужно будет сопоставить четное число кавычек, предшествующих совпадению, если вы хотите быть уверены, что вы не в строке (если не считать многострочной строки s и без экранированных меток кавычек).

0

3) Не совпадают, если в середине строки (спасибо nohat).

Возможно, вы можете написать reg ex, чтобы проверить «. * Boolean. *". Но что, если у вас есть цитата (") внутри строки? Итак, у вас больше работы, чтобы не исключать шаблон (\").

4) Не соответствуют, если в комментарии. (// или/* * /)

Для '//' вы можете иметь регулярное выражение, чтобы исключить //.* Но лучше было бы сначала поместить регулярное выражение для сравнения всей строки для // comments ((. *) (//.*)), а затем применить замену только на $ 1 (первый шаблон соответствия).

Для/* * /, это более сложно, так как это многострочный узор. Один из подходов может состоять в том, чтобы сначала запустить весь ваш код для соответствия многострочным комментариям, а затем вынуть только те части, которые не соответствуют ... что-то вроде ... (. *) (/*.**/) (. *). Но реальное регулярное выражение было бы еще более сложным, поскольку у вас не было бы одного, но более многострочного комментария.

Теперь, что, если у вас есть/* или */inside // block? (Я не знаю, почему у вас есть это ... но закон Мерфи говорит, что вы можете это иметь). Очевидно, есть какой-то выход, но моя идея - подчеркнуть, насколько плохо выглядит регулярное выражение.

Мое предложение здесь - использовать лексический инструмент для C++ и заменить токен Boolean на bool. Твои мысли?

0

Чтобы избежать написания полного парсера C в perl, вы пытаетесь найти баланс. В зависимости от того, насколько сильно меняются изменения, я был бы склонен делать что-то вроде очень ограничивающего s ///, а затем все, что по-прежнему соответствует/Boolean /, записывается в файл исключений для принятия решений по человеческому. Таким образом, вы не пытаетесь разобрать средние строки C, многострочный комментарий, условный скомпилированный текст и т. Д., Которые могут присутствовать.

0
  1. ...
  2. ...
  3. Не совпадают, если в середине строки (спасибо nohat).
  4. Не совпадают, если в комментарии. (// или/** /)

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

Теперь, я не знаю точные синтаксические правила для комментариев и строк в C++, так что следующий будет неточным и полностью undebugged, но это даст вам представление о сложности вы до против.

my $line_comment  = qr! (?> // .* \n?) !x; 
my $multiline_comment = qr! (?> /\* [^*]* (?: \* (?: [^/*] [^*]*)?)*)* \*/) !x; 
my $string   = qr! (?> " [^"\\]* (?: \\ . [^"\\]*)* ") !x; 
my $boolean_type  = qr! (?<!:) \b Boolean \b !x; 

$code =~ s{ \G (
     $line_comment 
    | $multiline_comment 
    | $string 
    | ($boolean_type) 
    | . 
) }{ 
    defined $2 ? 'bool' : $1 
}gex; 

Пожалуйста, не спрашивайте меня, чтобы объяснить это во всех его тонкостях, это заняло бы мне день и другой. Просто купите и прочитайте Jeff   Friedl's Mastering Regular Expressions, если вы хотите точно понять, что здесь происходит.

0

«„Boolean“в середине строки» часть звучит немного вряд ли, я бы проверить сначала, если есть любое вхождение его в коде с чем-то вроде

m/"[^"]*Boolean[^"]*"/ 

И если ни один, ни несколько, просто проигнорируйте этот случай.

1
#define Boolean bool 

Позвольте препроцессору позаботиться об этом. Каждый раз, когда вы видите логическое значение, вы можете вручную его исправить или надеяться, что регулярное выражение не сделает ошибку. В зависимости от того, сколько макросов вы используете, вы можете сбросить из cpp.