查找和检索连续匹配

问题描述 投票:1回答:2

假设我想匹配一个字符串,该字符串应该只包含符合特定(正则表达式)模式的部分,并在循环中检索元素。为此,似乎发明了Matcher.find()。但是,find将匹配任何字符串,而不仅仅是模式之后的字符串,因此会跳过中间字符。

所以 - 例如 - 我想以这样的方式匹配\\p{Xdigit}{2}(两个十六进制数字):

  • aabb比赛;
  • _aabb不匹配;
  • aa_bb不匹配;
  • aabb_不匹配。

通过使用find(或对正则表达式的任何其他迭代调用),我可以直接处理数组中的每个字节。所以我想在匹配后分别处理aabb

好吧,就是这样,这样做最优雅的方式赢得了接受。


笔记:

  • 十六进制解析只是简单重复模式的一个例子;
  • 我希望将正则表达式保持在匹配元素所需的最小值;
  • 是的,我知道使用(\\p{XDigit}{2})*,但我不想扫描字符串两次(因为它应该可用于巨大的输入字符串)。
java regex
2个回答
1
投票

您似乎希望获得出现在字符串开头或成功匹配后的所有(多个)匹配项。您可以将\G运算符与前瞻相结合,以确保字符串仅匹配某些重复模式。

使用

(?:\G(?!^)|^(?=(?:\p{XDigit}{2})*$))\p{XDigit}{2}

regex demo

细节

  • (?: - 一个有两个选择的非捕获组的开始: \G(?!^) - 上一次成功比赛的结束 | - 或 ^(?=(?:\p{XDigit}{2})*$) - 一个字符串(^)的开头,后面跟着0+次出现的\p{XDigit}{2}模式直到字符串的末尾($
  • ) - 非捕获组的结束
  • \p{XDigit}{2} - 2个十六进制字符。

Java demo

String regex = "(?:\\G(?!^)|^(?=(?:[0-9a-fA-F]{2})*$))[0-9a-fA-F]{2}";
String[] strings = {"aabb","_aabb","aa_bb", "aabb_"}; 
Pattern pattern = Pattern.compile(regex);
for (String s : strings) {
    System.out.println("Checking " + s);
    Matcher matcher = pattern.matcher(s);
    List<String> res = new ArrayList<>();
    while (matcher.find()) {
        res.add(matcher.group(0));
    }
    if (res.size() > 0) {
        System.out.println(res);
    } else {
        System.out.println("No match!");
    }
}

输出:

Checking aabb
[aa, bb]
Checking _aabb
No match!
Checking aa_bb
No match!
Checking aabb_
No match!

-1
投票

好吧,我可能最终有一个头脑风暴:想法是从while循环的条件中删除find()方法。相反,我应该只保留一个包含位置的变量,并且只在处理完整个字符串时停止解析。该位置还可用于生成更具信息性的错误消息。

该位置从零开始,并更新到比赛结束。每次找到新的匹配时,将匹配的开始与位置进行比较,即最后一次匹配的结束。如果出现以下错误:

  1. 找不到模式;
  2. 找到模式,但不是在最后一场比赛结束时。

码:

private static byte[] parseHex(String hex){
        byte[] bytes = new byte[hex.length() / 2];
        int off = 0;

        // the pattern is normally a constant
        Pattern hexByte = Pattern.compile("\\p{XDigit}{2}");
        Matcher hexByteMatcher = hexByte.matcher(hex);
        int loc = 0;
        // so here we would normally do the while (hexByteMatcher.find()) ...
        while (loc < hex.length()) {

            // optimization in case we have a maximum size of the pattern
            hexByteMatcher.region(loc, loc + 2);

            // instead we try and find the pattern, and produce an error if not found at the right location
            if (!hexByteMatcher.find() || hexByteMatcher.start() != loc) {
                // only a single throw, message includes location
                throw new IllegalArgumentException("Hex string invalid at offset " + loc);
            }
            // the processing of the pattern, in this case a double hex digit representing a byte value
            bytes[off++] = (byte) Integer.parseInt(hexByteMatcher.group(), 16);

            // set the next location to the end of the match
            loc = hexByteMatcher.end();
        }

        return bytes;
 }

可以通过将\\G(最后一个匹配的结尾)添加到正则表达式来改进该方法:\\G\\p{XDigit}{2}:这样,如果从最后一个匹配的结尾或字符串的开头开始找不到模式,则正则表达式将立即失败。

对于具有预期最大大小(在这种情况下为2)的正则表达式,当然也可以调整需要匹配的区域的末尾。

© www.soinside.com 2019 - 2024. All rights reserved.