что такое регулярное выражение для обнаружения цикла for и while в коде Java - PullRequest
1 голос
/ 21 ноября 2010

Что такое регулярное выражение для обнаружения цикла for и другое для определения цикла while. хотите обнаружить конструкции for(--;--;--) и while (--comparison operator --).

Ответы [ 7 ]

11 голосов
/ 21 ноября 2010

Вы не можете сделать это с помощью регулярных выражений.Вам нужно проанализировать код с помощью правильного парсера.

5 голосов
/ 22 ноября 2010

Те люди, которые используют \s в Java для обнаружения пробелов в коде Java, делают по крайней мере одну, а может и несколько ошибок.

Прежде всего, идея компилятора Java о собственном пробеле не соответствует тому, что \s соответствует в Java. Вы можете получить доступ к Java Character.isWhitespace() через свойство \p{JavaWhitespace}.

Во-вторых, Java не позволяет \s соответствовать пробелам Юникода; как реализовано в классе Java Pattern, \s соответствует только пробелам ASCII. На самом деле, Java не поддерживает никаких свойств, соответствующих пробелам Юникода.

Вот таблица, показывающая некоторые проблемные области:

                      000A    0085    00A0    2029
                      J  P    J  P    J  P    J  P
                \s    1  1    0  1    0  1    0  1
               \pZ    0  0    0  0    1  1    1  1
            \p{Zs}    0  0    0  0    1  1    0  0
         \p{Space}    1  1    0  1    0  1    0  1
         \p{Blank}    0  0    0  0    0  1    0  0
    \p{Whitespace}    -  1    -  1    -  1    -  1
\p{javaWhitespace}    1  -    0  -    0  -    1  -
 \p{javaSpaceChar}    0  -    0  -    1  -    1  -

На оси X вы видите четыре разных кодовых точки:

U+000A: LINE FEED (LF)
U+0085: NEXT LINE (NEL)
U+00A0: NO-BREAK SPACE
U+2029: PARAGRAPH SEPARATOR

У оси Y есть восемь различных тестов регулярных выражений, в основном свойства. Для каждой из этих кодовых точек есть и столбец J-результатов для Java, и столбец P-результатов для Perl или любого другого обработчика регулярных выражений на основе PCRE.

Это большая проблема. Java просто испорчена, давая «неправильные» ответы в соответствии с существующей практикой, а также в соответствии с Unicode. Кроме того, Java даже не дает вам доступа к реальным свойствам Unicode. Для записи это кодовые точки со свойством пробела Unicode:

% unichars '\pP{Whitespace}'
0009 CHARACTER TABULATION
000A LINE FEED (LF)
000B LINE TABULATION
000C FORM FEED (FF)
000D CARRIAGE RETURN (CR)
0020 SPACE
0085 NEXT LINE (NEL)
00A0 NO-BREAK SPACE
1680 OGHAM SPACE MARK
180E MONGOLIAN VOWEL SEPARATOR
2000 EN QUAD
2001 EM QUAD
2002 EN SPACE
2003 EM SPACE
2004 THREE-PER-EM SPACE
2005 FOUR-PER-EM SPACE
2006 SIX-PER-EM SPACE
2007 FIGURE SPACE
2008 PUNCTUATION SPACE
2009 THIN SPACE
200A HAIR SPACE
2028 LINE SEPARATOR
2029 PARAGRAPH SEPARATOR
202F NARROW NO-BREAK SPACE
205F MEDIUM MATHEMATICAL SPACE
3000 IDEOGRAPHIC SPACE

Если хотите, можете взять программу unichars и поиграть с ней и сопутствующими программами, uniprops и uninames . Я еще не добавил свойства только для Java, но собираюсь. Слишком много неприятных сюрпризов, подобных описанным выше.

Можно ли поверить, что в Java есть свойство \p{javaJavaIdentifierStart}? Я не шучу. Но вы не поверите, что символы, которые компилятор фактически позволяет вам использовать в идентификаторах; на самом деле вы бы не Кто-то не обращал внимания. Снова. (

4 голосов
/ 22 ноября 2010

Вы можете проанализировать почти все с помощью современного (в стиле PCRE) регулярного выражения.Тем не менее, синтаксический анализ некоторых вещей правильно часто патологически трудно.Легко создать небольшое, краткое регулярное выражение для соответствия только определенным видам просто отформатированных для циклов:

for\s*\([^;]*?;[^;]*?;[^)]*?\)

Но что происходит, когда вы сталкиваетесь с чем-то подобным?

int i = 0;
for(
        String s = "for(0;1;2)";
        s.indexOf(String.valueOf(i)) != -1;
        i++ // increment the i variable ;-)
   )

Лучше использовать полнофункциональный специализированный синтаксический анализатор Java, если вам нужна 100% надежность.Статья java.net Анализ исходного кода с использованием API-интерфейсов Java 6 дает отправную точку для одного из способов надежного анализа исходного кода Java.


В ответ на комментарий Taz:

Я сделал это с .*for(.*;.*;.*).* что может быть не так с этим?

Предполагая, что все циклы for, которые вы хотите сопоставить, имеют:

  1. без разрывов строк в них,
  2. без встроенных / завершающих комментариев
  3. без букв "string" или 'c'haracter в них

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

.*for\s*(.*;.*;.*).*

Однако, как указывает в его ответ на этот вопрос, \s* не являетсяСовершенно правильный способ учета пробелов в исходном коде Java, поскольку исходный код Java поддерживает типы пробелов Unicode, которые \s не допускает.Опять же, если вам нужна 100% надежность, лучше выбрать полноценный синтаксический анализатор исходного кода Java.

Убедитесь, что вы отключили (или не включили) опцию «точка соответствует новой строке» в вашем анализаторе(например, DOTALL или Singleline ).В противном случае ваше регулярное выражение может совпадать по нескольким строкам, что может привести к неправильному совпадению регулярного выражения.

0 голосов
/ 22 ноября 2010

Регулярные выражения могут анализировать только обычные (Ch-3) языки. Ява не является обычным языком, она как минимум не зависит от контекста (Ch-2), может быть, даже контекстно-зависимая (Ch-1).

0 голосов
/ 22 ноября 2010

Для петель проще всего обнаружить:

for *\(.*;.*;.*)

Хотя циклы немного сложнее, так как есть два способа сделать это. Если вы хотите использовать формат, который вы указали выше, это должно работать:

while *\(.*(<|>|<=|>=|==|!=).*\)

Однако, это не обнаруживает условия, которые зависят от логического значения переменной или логического результата от метода, поэтому эта версия будет немного проще и больше соответствует:

while *\(.*\)
0 голосов
/ 22 ноября 2010

Я думаю, что регулярные выражения, заданные СП, содержат дополнительный знак вопроса.

Вот моя версия:

for\s*\([^;]*;[^;]*;[^)]*\)

while\s*\(.*?\) правильно, но

while\s*\([^)]*\) должно быть быстрее.

0 голосов
/ 21 ноября 2010
for ?\(.*?;.*?;.*?\)
while ?\(.+?\)

Если код будет чем-то серьезно сложным (кроме того, чтобы сказать: происходит ли этот цикл где-нибудь в коде), используйте вместо этого парсер.

Зачем нам это нужно? Вот. И мне нужно обнаружить, что есть оператор сравнения в цикле while

Если бы я покинул? тогда это будет соответствовать for ( for(this;that;theother)

Я обновил цикл while, чтобы использовать +

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...