gpt4 book ai didi

java - Java正则表达式需要新鲜的眼光,这太贪婪了

转载 作者:行者123 更新时间:2023-11-30 05:56:45 24 4
gpt4 key购买 nike

我有一个以下形式的字符串:

canonical_class_name[key1="value1",key2="value2",key3="value3",...] 

目的是捕获组中的canonical_class_name,然后交替键=值组。目前它与测试字符串不匹配(在下面的程序中,testString)。

必须至少有一个键/值对,但可能有很多这样的对。

问题:目前正则表达式正确地获取规范类名和第一个键,但随后它会吞噬所有内容,直到最后一个双引号,如何让它惰性地获取键值对?

这是以下程序组合而成的正则表达式:

(\S+)\[\s*(\S+)\s*=\s*"(.*)"\s*(?:\s*,\s*(\S+)\s*=\s*"(.*)"\s*)*\]

根据您的喜好,您可能会发现程序版本更容易阅读。

如果我的程序传递了字符串:

org.myobject[key1=\"value1\", key2=\"value2\", key3=\"value3\"]

...这些是我得到的组:

Group1 contains: org.myobject<br/>
Group2 contains: key1<br/>
Group3 contains: value1", key2="value2", key3="value3<br/>

还有一点,使用String.split()我可以简化表达式,但我将此作为一种学习经验来更好地理解正则表达式,所以我不想使用这样的捷径。

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

public class BasicORMParser {
String regex =
"canonicalName\\[ map (?: , map )*\\]"
.replace("canonicalName", "(\\S+)")
.replace("map", "key = \"value\"")
.replace("key", "(\\S+)")
.replace("value", "(.*)")
.replace(" ", "\\s*");

List<String> getGroups(String ormString){
List<String> values = new ArrayList();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(ormString);
if (matcher.matches() == false){
String msg = String.format("String failed regex validiation. Required: %s , found: %s", regex, ormString);
throw new RuntimeException(msg);
}
if(matcher.groupCount() < 2){
String msg = String.format("Did not find Class and at least one key value.");
throw new RuntimeException(msg);
}
for(int i = 1; i < matcher.groupCount(); i++){
values.add(matcher.group(i));
}
return values;
}
}

最佳答案

您自己实际上已经回答了这个问题:让他们变得懒惰。也就是说,使用惰性(又名非贪婪不情愿)量词。只需将每个 (\S+) 更改为 (\S+?),并将每个 (.*) 更改为 (.*?) 。但如果是我,我会更改这些子表达式,这样它们就永远不会匹配太多,无论贪婪程度如何。例如,您可以使用 ([^\s\[]+) 作为类名,使用 ([^\s=]+) 作为键,使用 "([^"]*)" 为值。

不过,我认为这并不能解决您真正的问题。一旦你得到它并正确匹配所有键/值对,你会发现它只捕获第一对(组#2和#3)和最后对(组#3)。 4 和 #5)。这是因为,每次重复 (?:\s*,\s*(\S+)\s*=\s*"(.*)"\s*)* 时,这两个组它们的内容被覆盖,并且它们在上一次迭代中捕获的任何内容都会丢失。这是无法回避的,这至少是一个两步操作。例如,您可以将所有键/值对作为一个 block 进行匹配,然后分解各个对。

还有一件事。这一行:

if(matcher.groupCount() < 2){

...可能没有按照您的想法进行。 groupCount() 是 Pattern 对象的静态属性;它告诉正则表达式中有多少个捕获组。无论匹配成功还是失败,groupCount() 都将始终返回相同的值 - 在本例中为 5。如果匹配成功,某些捕获组可能为空(表示它们没有参加比赛),但总会有五个。


编辑:我怀疑这就是您最初尝试的:

Pattern p = Pattern.compile(
"(?:([^\\s\\[]+)\\[|\\G)([^\\s=]+)=\"([^\"]*)\"[,\\s]*");

String s = "org.myobject[key1=\"value1\", key2=\"value2\", key3=\"value3\"]";
Matcher m = p.matcher(s);
while (m.find())
{
if (m.group(1) != null)
{
System.out.printf("class : %s%n", m.group(1));
}
System.out.printf("key : %s, value : %s%n", m.group(2), m.group(3));
}

输出:

class : org.myobject
key : key1, value : value1
key : key2, value : value2
key : key3, value : value3

理解正则表达式的关键是这部分:(?:([^\s\[]+)\[|\G)。在第一遍中,它匹配类名称和左方括号。之后,\G 接管,将下一场比赛锚定到上一场比赛结束的位置。

关于java - Java正则表达式需要新鲜的眼光,这太贪婪了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6741365/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com