用Java匹配正则表达式组

用Java匹配正则表达式组,java,regex,string,regex-group,Java,Regex,String,Regex Group,我正试图通过使用组来拆分一行与regex的代码,但它并没有像我预期的那样工作。 例如,我想匹配以下行: 例1:temp name(这是数据) 还有: 例2:temp name() 我使用了这个正则表达式: [\s]*temp[\s]+[\s]*([A-Za-z]+)[\s]*[(]\s*(.*)+[)]\s*[{]\s* 这意味着:抓取以temp开头的任何内容,然后将“名称”放入第1组,然后抓取括号内的任何内容,将其放入第2组 但是,第2组始终为空 这是我获取数据的代码: Pattern PA

我正试图通过使用组来拆分一行与regex的代码,但它并没有像我预期的那样工作。
例如,我想匹配以下行:

例1:
temp name(这是数据)

还有:

例2:
temp name()

我使用了这个正则表达式:

[\s]*temp[\s]+[\s]*([A-Za-z]+)[\s]*[(]\s*(.*)+[)]\s*[{]\s*
这意味着:抓取以
temp
开头的任何内容,然后将“名称”放入第1组,然后抓取括号内的任何内容,将其放入第2组

但是,第2组始终为空

这是我获取数据的代码:

Pattern PATTERN = Pattern.compile("[\\s]*temp[\\s]+[\\s]*([A-Za-z]+)[\\s]*[(]\\s*(.*)+[)]\\s*");

Matcher m = PATTERN.matcher("temp name(this is the data)");
m.matches();
String name = m.group(1);
String data = m.group(2); // always empty

我做错了什么?

您的模式不匹配,因为它需要在末尾使用一个开放的花括号,但您的输入没有花括号

忽略这个小问题,主要问题是捕获组
(.*)+
之后的小
+
。加号需要一个或多个匹配项
*
,返回的组是许多匹配项中的最后一个。术语
*
是贪婪的,所以它会消耗掉括号内的所有东西。再次匹配的唯一方法是不消耗任何东西。所以第二组的最后一个匹配是空白的

要解决此问题,请删除组2后的
+

Pattern PATTERN = Pattern.compile("\\s*temp\\s+([A-Za-z]+)\\s*[(]\\s*(.*)[)]\\s*");
还要注意我是如何从正则表达式中删除其他不必要的字符的,例如单字符字符类-即
[\\s]
\s
相同。而
\\s+\\s*
\\s+
完全相同,因为
+
是贪婪的


我还删除了尾随的花括号,如果您的输入数据确实有它,您可以恢复它(您的问题显示输入了
“temp name(这是数据)”
,它没有尾随的花括号)。

[\s]
\s

[\s]+[\s]*
等同于
\s+

[(]
等同于
\(
(与
[)]
[}]
相同)

这将使您的regexp成为:

\s*temp\s+([A-Za-z]+)\s*\(\s*(.*)+\)\s*{\s*

假设您确实想要匹配
临时名称(…){
(您的regexp正在查找
{
,而在您的问题中您没有指定):

(.*)+
是您的问题。您的意思是:“匹配任意数量(包括0个)的聊天参与者,并将其放入捕获组,至少重复一次”

默认情况下,Regexp是贪婪的(=它们消耗尽可能多),因此捕获组将首先包含两个括号内的所有内容,然后
+
将再次尝试匹配整个组,并将其与
(emtpy字符串)匹配因为这符合捕获组的模式。这将延长捕获组的有效期


您想要的是
\s*temp\s+([A-Za-z]+)\s*(\s*(.*)\)\s*{\s*
您的正则表达式应该是:

Pattern pattern = Pattern.compile("\\s*temp\\s+([A-Za-z]+)\\s*[(]\\s*(.*)[)]\\s*");
您有
(.*)+
,这意味着一个或多个
*
匹配项。这将导致未捕获任何内容

测试:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Example {

    public static void main(String[] args) {

        Pattern pattern = Pattern.compile("\\s*temp\\s+([A-Za-z]+)\\s*[(]\\s*(.*)[)]\\s*");

        Matcher m = pattern.matcher("temp name(this is the data)");
        if(m.matches()) {
            System.out.println(m.group(1));
            System.out.println(m.group(2));
        }
    }
}
输出:

name
this is the data

获取空组的原因是,每次在()之间放置某个内容时,即使它是嵌套的,也会创建多个捕获组

要使一个组不被捕获,您可以使用?:例如
(?:sometest(这是我们想要的值))
将只返回一个组,而
(sometest(这是我们想要的值))
将返回两个组

对于您特定的正则表达式,我已经对其进行了改进和简化,因为您有不需要的捕获组

简单解决方案:

\\s*temp\\s+([A-Za-z]+)\\s*\\(\\s*(.*)\\\\\\s*\{\\s*

根据输入:

Ex. #1: temp name(this is the data) {
Ex. #2: temp name() {
$1=名称,$2=数据

请注意,您的正则表达式包含一个尾随的大括号。您可以修改正则表达式使其匹配,而不使用它,这将导致:

\\s*temp\\s+([A-Za-z]+)\\s*\\(\\s*(.*)\\\\\\s*


Oh Foo.谢谢@SebastianProske-fixedIs为(and)创建数组而不是像这样简单地将它们作为单个字符转义有意义吗?
\\s*temp\\s+([a-Za-z]+)\\s*\\(\\s*(.*)\\\\\\s*.\\\\\\s*
@yoseflow这是一种风格。
[(]
\\(
在效果和字符数上是等效的。如果长度不同,我更喜欢较短的,但因为它们是相同的,我打破了可读性上的限制。我个人觉得
[(]
更容易阅读。此外,一些字符在像这样“转义”时看起来很酷,例如
[*]
,这总是让我想起哈,实际上我也有同样的习惯,更喜欢括号而不是转义符,但我想知道这是否会对性能造成影响。@yosefrow性能会有一点影响,因为引擎必须处理大小为1的字符列表,而不是单个字符。我只是做了一些基准测试,然后在性能危急的情况下(如自动股票交易),在订单上使用字符类转义成本为50纳秒你可能会担心,但对于正常的商业情况,没有人会在意或注意到。但其他程序员将不得不阅读并可能调试你的正则表达式,因此可读性具有真正的商业价值。必须节省这些纳秒;)