多个匹配分隔符

时间:2015-12-14 13:35:22

标签: java regex

这是我的正则表达式:

([+-]*)(\\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###

我的情况我可以使用matcher.find()方法,这可以做到这一点,但它会接受这样的输入:+1day###+1month这对我无效。

有什么想法吗?这可以通过多个IF条件和多个检查开始和结束索引来解决,但我正在寻找优雅的解决方案。

修改

以下评论^\s*(([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$中建议的正则表达式将部分地解决问题,但如果我在下面的代码中使用它,则会返回与我正在寻找的结果不同的结果。 问题是我不能使用(*my regex*)+,因为它会匹配整个事情。

解决方案可以是将整个输入与^\s*(([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$匹配,然后使用([+-]*)(\\d+)\\s*([a-zA-Z]+)matcher.find()matcher.group(i)来提取每个匹配及其组。但我一直在寻找更优雅的解决方案。

4 个答案:

答案 0 :(得分:7)

这应该适合你:

<h2>Course Visibility and Sorting</h2>

 <p>Instructors: The «courses» will be sorted first by availability (courses     
that have been made available to students will show up first followed by courses     
not available to students), then by semester. For example, if you are teaching a     
course in the current semester and it is available to students, it will 
appear at the top of your course listing. If you are teaching a course in      
the current semester and it is not available to students, it will appear 
after all the courses that are available to students. </p>

<h2>Students:</h2>
<br>

first year students<br>
second year students<br>
post graduate<br>

首先,通过添加开始和结束锚点(^\s*(([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$ ^),模式不允许在匹配之前或之后的任何地方出现无效字符。

接下来,我在重复模式($)之前和之后包含了可选的空格。

最后,将整个模式封装在转发器中,以便它可以连续多次出现(\s*)。

另一方面,请注意,我还建议您将(...)+更改为[+-]*,以便只能进行一次。

Online Demo

答案 1 :(得分:0)

您可以使用id来匹配字符串的开头/结尾

^$

https://regex101.com/r/lM7dZ9/2

有关示例,请参阅^\s*(?:([+-]?)(\d+)\s*([a-z]+)\s*)+$ 。基本上,你只需要允许模式重复并强制在匹配之间没有任何空格。

结合行开始/结束匹配,你就完成了。

答案 2 :(得分:0)

您可以在Java中使用String.matchesMatcher.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();
    }
}

答案 3 :(得分:0)

您可以这样继续:

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");
}

\G锚点匹配字符串的开头或上一个匹配后的位置。在这种模式中,它确保所有匹配都是连续的。如果到达字符串的末尾,则表明该字符串从开始到结束都是有效的。