Java中的正则表达式命名组
Posted
技术标签:
【中文标题】Java中的正则表达式命名组【英文标题】:Regex Named Groups in Java 【发布时间】:2010-09-29 18:11:06 【问题描述】:据我了解,java.regex
包不支持命名组 (http://www.regular-expressions.info/named.html),所以有人可以将我指向支持的第三方库吗?
我查看了jregex,但它的最后一个版本是在 2002 年,它在 java5 下对我不起作用(诚然我只是简单地尝试过)。
【问题讨论】:
你的理解有误。 JDK7 处理命名组。 @tchrist 2009 年没有 JDK7。 注意:这是discussed on Meta,12 年后。 【参考方案1】:(更新:2011 年 8 月)
正如geofflane 在his answer 中提到的那样,Java 7 now support named groups。tchrist 在评论中指出支持是有限的。 他在他的精彩回答“Java Regex Helper”中详细说明了局限性
September 2010 in Oracle's blog 中提供了 Java 7 正则表达式命名组支持。
在 Java 7 的正式版本中,支持命名捕获组的结构是:
(?<name>capturing text)
定义一个命名组“名称”\k<name>
反向引用命名组“名称”$name
引用 Matcher 替换字符串中捕获的组Matcher.group(String name)
返回给定“命名组”捕获的输入子序列。
Java 7 之前的其他替代方案是:
Google named-regex(参见 John Hardy 的 answer)Gábor Lipták 提到(2012 年 11 月)该项目可能不活跃(使用 several outstanding bugs),可以考虑使用其 GitHub fork。 jregex(见Brian Clozel的answer)(原始答案:2009 年 1 月,接下来的两个链接现已断开)
您不能引用命名组,除非您编写自己的正则表达式版本...
这正是Gorbush2 did in this thread。
Regex2
(有限的实现,正如tchrist 再次指出的那样,因为它只查找 ASCII 标识符。tchrist 详细说明了限制:
每个同名只能有一个命名组(您并不总是可以控制它!)并且不能将它们用于正则表达式内递归。
注意:您可以在 Perl 和 PCRE 正则表达式中找到真正的正则表达式递归示例,如 Regexp Power、PCRE specs 和 Matching Strings with Balanced Parentheses 幻灯片中所述)
例子:
字符串:
"TEST 123"
正则表达式:
"(?<login>\\w+) (?<id>\\d+)"
访问
matcher.group(1) ==> TEST
matcher.group("login") ==> TEST
matcher.name(1) ==> login
替换
matcher.replaceAll("aaaaa_$1_sssss_$2____") ==> aaaaa_TEST_sssss_123____
matcher.replaceAll("aaaaa_$login_sssss_$id____") ==> aaaaa_TEST_sssss_123____
(从实现中提取)
public final class Pattern
implements java.io.Serializable
[...]
/**
* Parses a group and returns the head node of a set of nodes that process
* the group. Sometimes a double return system is used where the tail is
* returned in root.
*/
private Node group0()
boolean capturingGroup = false;
Node head = null;
Node tail = null;
int save = flags;
root = null;
int ch = next();
if (ch == '?')
ch = skip();
switch (ch)
case '<': // (?<xxx) look behind or group name
ch = read();
int start = cursor;
[...]
// test forGroupName
int startChar = ch;
while(ASCII.isWord(ch) && ch != '>') ch=read();
if(ch == '>')
// valid group name
int len = cursor-start;
int[] newtemp = new int[2*(len) + 2];
//System.arraycopy(temp, start, newtemp, 0, len);
StringBuilder name = new StringBuilder();
for(int i = start; i< cursor; i++)
name.append((char)temp[i-1]);
// create Named group
head = createGroup(false);
((GroupTail)root).name = name.toString();
capturingGroup = true;
tail = root;
head.next = expr(tail);
break;
【讨论】:
上面的两个链接好像都坏了? 这段代码有问题。它正在寻找 ASCII 标识符。这是错误的。它应该在标识符中查找 Java 允许的任何内容! 仅供参考,因为你看起来很认真,有限的部分不是关于 ASCII 与 Unicode 名称,而是关于每个相同名称只能有一个命名组(你没有t 始终可以控制!)并且无法将它们用于正则表达式内递归。 @tchrist:感谢您的精确度(包括在内)。我还添加了一个链接,返回您关于“Java Regex helper”的出色答案(已投票)。 Java 中没有 Matcher 对象的 matcher.name(int index) 方法??【参考方案2】:是的,但是破解太阳课程很麻烦。有一个更简单的方法:
http://code.google.com/p/named-regexp/
named-regexp 是 标准 JDK 正则表达式 实施,与单 处理命名捕获的目的 .net 样式的组: (?...)。
它可以与 Java 5 和 6 一起使用 (使用泛型)。
Java 7 将处理命名捕获 组,所以这个项目并不意味着 持续下去。
【讨论】:
可惜不能在 GWT 中使用。 查看这个项目的GitHub fork,它修复了原来的几个错误。它也托管在 Maven Central 中。 请注意,Github 上的 tony19 fork 从 0.1.8 开始无法在 android 上运行。 @RubberMallet,Android 特有的问题现在是 fixed,并将在 0.1.9 中出现。【参考方案3】:jregex 遇到了什么问题? 它在 java5 和 java6 下对我来说效果很好。
Jregex 做得很好(即使最后一个版本是 2002 年的),除非you want to wait for javaSE 7。
【讨论】:
【参考方案4】:对于迟到的人:Java 7 添加了命名组。 Matcher.group(String groupName) documentation.
【讨论】:
【参考方案5】:对于那些运行 pre-java7 的用户,joni(Oniguruma regexp 库的 Java 端口)支持命名组。文档很少,但对我们来说效果很好。 二进制文件可通过 Maven (http://repository.codehaus.org/org/jruby/joni/joni/) 获得。
【讨论】:
我对上面 Ryan 提到的 joni 选项非常感兴趣——你有任何使用命名捕获组的代码 sn-ps——我已经设法让基本匹配和搜索正常工作——但我看不到我将使用哪种方法来访问 groupNames 或使用组名获取捕获的值。【参考方案6】:一个有点老的问题,但我发现自己也需要这个,并且上面的建议是不合适的 - 因此 - 我自己开发了一个薄包装:https://github.com/hofmeister/MatchIt
【讨论】:
以上是关于Java中的正则表达式命名组的主要内容,如果未能解决你的问题,请参考以下文章