- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个以下形式的字符串:
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/
我是一名优秀的程序员,十分优秀!