Незакрытый символьный класс рядом с индексом nnn - PullRequest
5 голосов
/ 14 ноября 2011

Я заимствую довольно сложное регулярное выражение из некоторых реализаций PHP Textile (с открытым исходным кодом, должным образом приписанным) для простой, не полностью функциональной реализации Java, textile4j, которую я портирую на github и синхронизирую с Maven central ( оригинальный код был написан для предоставления плагина для blojsom, платформы блогов на Java; это часть больших усилий по обеспечению доступности зависимостей blojsom в Maven Central).

К сожалению, выражения регулярного выражения текстиля (хотя они работают в контексте preg_replace_callback в PHP) завершаются ошибкой в ​​Java со следующим исключением:

java.util.regex.PatternSyntaxException: Unclosed character class near index 217

Утверждение очевидно, решение неуловимо.

Вот необработанное многострочное регулярное выражение из реализации PHP:

return preg_replace_callback('/
    (^|(?<=[\s>.\(])|[{[]) # $pre
    "                      # start
    (' . $this->c . ')     # $atts
    ([^"]+?)               # $text
    (?:\(([^)]+?)\)(?="))? # $title
    ":
    ('.$this->urlch.'+?)   # $url
    (\/)?                  # $slash
    ([^\w\/;]*?)           # $post
    ([\]}]|(?=\s|$|\)))
    /x',callback,input);

Умно, я заставил текстильный класс "показать мне код", используемый в этом регулярном выражении, с простым echo, что привело к следующему, довольно длинному регулярному выражению:

(^|(?<=[\s>.\(])|[{[])"((?:(?:\([^)]+\))|(?:\{[^}]+\})|(?:\[[^]]+\])|(?:\<(?!>)|(?<!<)\>|\<\>|\=|[()]+(?! )))*)([^"]+?)(?:\(([^)]+?)\)(?="))?":([\w"$\-_.+!*'(),";\/?:@=&%#{}|\^~\[\]`]+?)(\/)?([^\w\/;]*?)([\]}]|(?=\s|$|\)))

Я обнаружил пару возможных областей, которые могут привести к ошибкам синтаксического анализа, используя онлайн-инструменты, такие как RegExr от gskinner и RegexPlanet . Однако ни одна из этих подробностей не исправляет ошибку.

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

Есть идеи?

Мне также любопытно, почему PHP не выдает подобную ошибку, например, я обнаружил, что одно «пассивное подвыражение» плохо обрабатывается с помощью RegExr, но оно не исправляет исключение Java и не изменяет поведение в PHP, показанный ниже.

В #title переключите сбежавшего парня:

        (?:\(([^)]+?)\)(?="))? # $title
        ...^
        (?:(\([^)]+?)\)(?="))? # $title
        ....^

Спасибо, Тим

edit: добавление интерпретации Java String (с выходами) для регулярного выражения Textile, как определено RegexPlanet ...

"(^|(?<=[\\s>.\\(])|[{[])\"((?:(?:\\([^)]+\\))|(?:\\{[^}]+\\})|(?:\\[[^]]+\\])|(?:\\<(?!>)|(?<!<)\\>|\\<\\>|\\=|[()]+(?! )))*)([^\"]+?)(?:\\(([^)]+?)\\)(?=\"))?\":([\\w\"$\\-_.+!*'(),\";\\/?:@=&%#{}|\\^~\\[\\]`]+?)(\\/)?([^\\w\\/;]*?)([\\]}]|(?=\\s|$|\\)))"

Ответы [ 2 ]

9 голосов
/ 15 ноября 2011

@ CodeJockey верен: в одном из ваших классов персонажей есть квадратная скобка, которую нужно экранировать. []] или [^]] в порядке, потому что ] является первым символом, отличным от отрицательного ^, но в Java неэкранированный [ в любом месте символьного класса является синтаксической ошибкой.

По иронии судьбы, оригинальное регулярное выражение содержит много обратных косых черт, которые не нужны даже в PHP. Он также избегает /, потому что это то, что он использует в качестве разделителя регулярных выражений. После того, как я отсеял все это, я предложил следующее регулярное выражение Java:

"(^|(?<=[\\s>.(])|[{\\[])\"((?:(?:\\([^)]+\\))|(?:\\{[^}]+\\})|(?:\\[[^]]+\\])|(?:<(?!>)|(?<!<)>|<>|=|[()]+(?! )))*)([^\"]+?)(?:\\(([^)]+?)\\)(?=\"))?\":([\\w\"$_.+!*'(),\";/?:@=&%#{}|^~\\[\\]`-]+?)(/)?([^\\w/;]*?)([]}]|(?=\\s|$|\\)))"

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

1 голос
/ 14 ноября 2011

Я не уверен, в чем именно заключается ваша проблема, но это может помочь:

В Java (и я считаю, что это уникально для Java), символ [ (не только ]символ) зарезервирован внутри символьных классов и должен быть экранирован.

Пересмотренное выражение, вероятно, должно быть похоже на следующее, чтобы быть Java-совместимым:

(^|(?<=[\s>.\(])|[{\[]) # $pre
"                       # start
(' . $this->c . ')      # $atts
([^"]+?)                # $text
(?:\(([^)]+?)\)(?="))?  # $title
":
('.$this->urlch.'+?)    # $url
(\/)?                   # $slash
([^\w\/;]*?)            # $post
([\]}]|(?=\s|$|\)))
/x

По сути, любоеместо, где большинство разновидностей регулярных выражений допускают класс символов, такой как [a-z,;[\]+-] - который будет соответствовать «либо буква a - z, либо запятая, точка с запятой, открытая или закрытая квадратная скобка, знак плюс или минус», которая должна фактическибыть [a-z,;\[\]+-] (экранировать [ с символом \)

Это требование экранирования обусловлено конструкциями символьного класса Java , пересечения и вычитания .

...