Java 带分隔符的多个匹配项
这是我的正则表达式:Java 带分隔符的多个匹配项,java,regex,Java,Regex,这是我的正则表达式: ([+-]*)(\\d+)\\s*([a-zA-Z]+) 第1组=符号 第2组=乘数 第3组=时间单位 问题是,我想匹配给定的输入,但它可以“链接”。因此,我的输入应该是有效的,当且仅当整个模式在这些出现之间没有任何重复(空白除外)。(只有一个匹配项或多个匹配项相邻,它们之间可能有空格) 有效例子: 1day +1day -1 day +1day-1month +1day +1month +1day +1month ###+1day+1month +
([+-]*)(\\d+)\\s*([a-zA-Z]+)
- 第1组=符号
- 第2组=乘数
- 第3组=时间单位
1day
+1day
-1 day
+1day-1month
+1day +1month
+1day +1month
###+1day+1month
+1day###+1month
+1day+1month###
###+1day+1month###
###+1day+1month###
无效示例:
1day
+1day
-1 day
+1day-1month
+1day +1month
+1day +1month
###+1day+1month
+1day###+1month
+1day+1month###
###+1day+1month###
###+1day+1month###
在我的情况下,我可以使用matcher.find()方法,这可以做到这一点,但它将接受如下输入:+1day\35;\35;+1个月
,这对我无效
有什么想法吗?这可以通过多个IF条件和多个开始和结束索引检查来解决,但我正在寻找优雅的解决方案
编辑
下面注释中建议的正则表达式([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$将部分起作用,但如果我在下面的代码中使用它,它返回的结果与我正在寻找的结果不同。
问题是我不能使用(*我的正则表达式*)+
,因为它将匹配整个内容
解决方案可以是使用
^\s*([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$
匹配整个输入,然后使用([+-]*)(\\d+)\\s*([a-zA-Z]+)
和匹配器.find()
和匹配器.group(i)
提取每个匹配项及其组。但我正在寻找更优雅的解决方案。这应该适合您:
^\s*(([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$
首先,通过添加开头和结尾锚定(^
和$
),模式将不允许在匹配之前或之后的任何位置出现无效字符
接下来,我在重复模式前后添加了可选的空格(\s*
)
最后,整个模式被封装在一个中继器中,这样它可以在一行中多次出现((…)+
)
另一方面,请注意,我还建议将[+-]*
更改为[+-]?
,这样它只能出现一次
您可以使用
^$
来匹配字符串的开头/结尾
^\s*(?:([+-]?)(\d+)\s*([a-z]+)\s*)+$
有关示例,请参见单元测试。基本上,您只需要允许模式重复,并强制在匹配之间除了空格之外没有其他内容发生
结合行开始/结束匹配,就完成了。您可以在Java中使用
String.matches
或Matcher.matches
来匹配整个区域
Java示例:
public class RegTest {
public static final Pattern PATTERN = Pattern.compile(
"(\\s*([+-]?)(\\d+)\\s*([a-zA-Z]+)\\s*)+");
@Test
public void testDays() throws Exception {
assertTrue(valid("1 day"));
assertTrue(valid("-1 day"));
assertTrue(valid("+1day-1month"));
assertTrue(valid("+1day -1month"));
assertTrue(valid(" +1day +1month "));
assertFalse(valid("+1day###+1month"));
assertFalse(valid(""));
assertFalse(valid("++1day-1month"));
}
private static boolean valid(String s) {
return PATTERN.matcher(s).matches();
}
}
你可以这样做:
String p = "\\G\\s*(?:([-+]?)(\\d+)\\s*([a-z]+)|\\z)";
Pattern RegexCompile = Pattern.compile(p, Pattern.CASE_INSENSITIVE);
String s = "+1day 1month";
ArrayList<HashMap<String, String>> results = new ArrayList<HashMap<String, String>>();
Matcher m = RegexCompile.matcher(s);
boolean validFormat = false;
while( m.find() ) {
if (m.group(1) == null) {
// if the capture group 1 (or 2 or 3) is null, it means that the second
// branch of the pattern has succeeded (the \z branch) and that the end
// of the string has been reached.
validFormat = true;
} else {
// otherwise, this is not the end of the string and the match result is
// "temporary" stored in the ArrayList 'results'
HashMap<String, String> result = new HashMap<String, String>();
result.put("sign", m.group(1));
result.put("multiplier", m.group(2));
result.put("time_unit", m.group(3));
results.add(result);
}
}
if (validFormat) {
for (HashMap item : results) {
System.out.println("sign: " + item.get("sign")
+ "\nmultiplier: " + item.get("multiplier")
+ "\ntime_unit: " + item.get("time_unit") + "\n");
}
} else {
results.clear();
System.out.println("Invalid Format");
}
String p=“\\G\\s*(?:([-+])(\\d+\\s*([a-z]+)|\\z)”;
Pattern RegexCompile=Pattern.compile(p,Pattern.CASE\u不区分大小写);
字符串s=“+1天1月”;
ArrayList结果=新建ArrayList();
Matcher m=RegexCompile.Matcher;
布尔值validFormat=false;
while(m.find()){
如果(m.组(1)=null){
//如果捕获组1(或2或3)为空,则表示第二个
//模式的分支已成功(即\z分支),并且结束
//已达到字符串的长度。
validFormat=真;
}否则{
//否则,这不是字符串的结尾,匹配结果为
//存储在ArrayList“results”中的“temporary”
HashMap结果=新建HashMap();
结果:①m组(1)放置(“符号”);
结果:put(“乘数”,m组(2));
结果:put(“时间单位”,m组(3));
结果。添加(结果);
}
}
if(有效格式){
对于(HashMap项:结果){
System.out.println(“签名:”+item.get(“签名”)
+\n乘数:“+item.get”(“乘数”)
+“\n时间单位:”+item.get(“时间单位”)+“\n”);
}
}否则{
结果:清晰();
System.out.println(“无效格式”);
}
\G
锚点匹配字符串的开头或上一次匹配后的位置。在这种模式中,它确保所有匹配都是连续的。如果到达字符串的结尾,则证明该字符串从头到尾都有效。Thx,用于回复。你说得对,但我描述得不对。如果我的输入有效,那么我需要为每个匹配提取符号、乘数和时间单位值。使用您的解决方案,它将返回“+1天+1个月”作为1个匹配,而不是两个“+1天”和“+1个月”,您当然可以循环遍历该匹配中的所有组。如果这不能很好地满足您的需要,那么只需多次调用matcher.find
和^\s*([+-]*)(\d+)\s*([a-zA-Z]+)
,每次传入下一个起始索引就可以了。