5

我从一些 PHP Textile 实现(开源,适当归因)中借用了一个相当复杂的正则表达式,用于一个简单但功能不完全的 Java 实现,textile4j,我将其移植到 github 并同步到 Maven 中心(原始代码是为 Java 博客平台 blojsom 提供一个插件;这是在 Maven Central 中提供 blojsom 依赖项的更大努力的一部分)。

不幸的是,纺织正则表达式(虽然它们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|$|\)))

我使用在线工具(例如gskinner 的 RegExrRegexPlanet)发现了几个可能导致解析错误的区域。但是,这些细节都不能解决该错误。

我怀疑其中一个字符类中隐藏了一个范围问题,或者隐藏在某个地方的 Unicode 顺序,但我找不到它。

有任何想法吗?

我也很好奇为什么 PHP 不会抛出类似的错误,例如,我发现一个“被动子表达式”使用 RegExr 处理得不好,但它没有修复 Java 异常,也没有改变 PHP 中的行为,如图所示以下。

#title切换转义的括号中:

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

谢谢,蒂姆

编辑:添加由RegexPlanet确定的 Textile 正则表达式的 Java 字符串解释(带有转义)...

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

2 回答 2

9

@CodeJockey 是正确的:您的一个字符类中有一个方括号需要转义。 []]或者[^]]是可以的,因为 the]是除否定之外的第一个字符,但在 Java中,字符类中 ^未转义的任何地方都是语法错误。[

具有讽刺意味的是,原始的正则表达式包含许多即使在 PHP 中也不需要的反斜杠。它也会转义/,因为这就是它用作正则表达式分隔符的原因。在清除所有这些之后,我想出了这个 Java 正则表达式:

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

我不知道它是否是最好的正则表达式,也不知道它是如何被使用的。

于 2011-11-15T09:00:33.323 回答
1

我不确定您的问题到底出在哪里,但这可能会有所帮助:

在 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 的联合、交集和减法字符类结构造成的。

于 2011-11-14T18:49:18.033 回答