Java Regex:“分解出”重复的子模式

tkqqtvp1  于 2023-02-15  发布在  Java
关注(0)|答案(3)|浏览(108)

我正在使用一个商业的闭源代码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模式?不要忘记,我所能做的只是提供一个模式字符串,我没有访问代码的权限。

6g8kf2rb

6g8kf2rb1#

从Java8开始,纯正则表达式的解决方案还不存在,\g可能会在未来的更新版本中得到支持。
如前所述,唯一的解决方案是字符串连接技术,但在您的情况下,这不是一个选项。
如果您告诉我们商业闭源代码Java应用程序的名称,也许我们可以为您提供更多帮助。

3hvapo4f

3hvapo4f2#

如果您可以在提交模式之前运行一些java代码,那么您可以使用apache.commons中的StrSubstitutor:

Map<String, String> valuesMap = new HashMap<>();
valuesMap.put("os", "(windows|linux|osx)");
valuesMap.put("name", "(?[^_]+)");
StrSubstitutor sub = new StrSubstitutor(valuesMap);

String template ="^(\n"+
        "    ( # pattern foo\n"+
        "        foo_${name}_${os}\n"+
        "    )\n"+
        "    |\n"+
        "    ( # pattern bar\n"+
        "        ${name}_bar_${os}_foo_${os}\n"+
        "    )\n"+
        ")$";
String regex = sub.replace(template);
System.out.println(regex);
s3fp2yjn

s3fp2yjn3#

正则表达式减少到^(?:foo_[^_]+|[^_]+_bar_(?:windows|(?:linu|os)x)_foo)_(?:windows|(?:linu|os)x)$

^ 
(?:
  foo_ [^_]+ 
| [^_]+ _bar_
  (?:
    windows
  | (?: linu | os )
    x
  )
  _foo
)
_
(?:
  windows
| (?: linu | os )
  x
)
$

相关问题