我正在使用一个商业的闭源代码Java应用程序,除了它所做的一切之外,它还允许通过提供正则表达式模式字符串来过滤文本字段。
我遇到的问题是,我经常发现自己在正则表达式中重复完全相同的子模式。
^(
( # pattern foo
foo_([^_]+)_(windows|linux|osx)
)
|
( # pattern bar
([^_]+)_bar_(windows|linux|osx)_foo_(windows|linux|osx)
)
)$
([^_]+)
和(windows|linux|osx)
部分经常重复。
这只是一个虚构的例子。原始的正则表达式更复杂,大约大20倍,并且有很多不同的重复。它变得有点难以阅读,因为重复的子模式只会在大小和数量上不断增长,而且当你试图修改一个重复的子模式时,你必须修改它的所有重复。
所以,我用regex101得到了这个
^(
( # a dummy option, defines some frequently used capture groups
(?!x)x # always false, so nothing matches this and the following groups ever
(?'name'[^_]+) # group "name"
(?'os'windows|linux|osx) # group "os"
)
|
( # pattern foo
foo_\g'name'_\g'os'
)
|
( # pattern bar
\g'name'_bar_\g'os'_foo_\g'os'
)
)$
regex101 save
现在所有的子模式都被命名了,每当我引用名称时,它们就会被替换为子模式字符串(例如\g'os'
被替换为(windows|linux|osx)
)。名称比相应的子模式短得多,它们也很清楚,您只需修改一次子模式,修改就可以应用到正则表达式中的任何地方。
这个改进版本的问题是,虽然它是一个有效的PHP pcre正则表达式,但它是无效的Java正则表达式。除了正则表达式中的注解和虚线外,Java不支持\g
,如Comparison to Perl 5中所述。
有没有什么方法可以像Java Regex那样“分解”重复的regex模式?不要忘记,我所能做的只是提供一个模式字符串,我没有访问代码的权限。
3条答案
按热度按时间6g8kf2rb1#
从Java8开始,纯正则表达式的解决方案还不存在,
\g
可能会在未来的更新版本中得到支持。如前所述,唯一的解决方案是字符串连接技术,但在您的情况下,这不是一个选项。
如果您告诉我们商业闭源代码Java应用程序的名称,也许我们可以为您提供更多帮助。
3hvapo4f2#
如果您可以在提交模式之前运行一些java代码,那么您可以使用apache.commons中的StrSubstitutor:
s3fp2yjn3#
正则表达式减少到
^(?:foo_[^_]+|[^_]+_bar_(?:windows|(?:linu|os)x)_foo)_(?:windows|(?:linu|os)x)$