【问题标题】:regex include and exclude escape sequences正则表达式包含和排除转义序列
【发布时间】:2014-02-03 19:17:49
【问题描述】:

我正在尝试找到一个采用以下数据的正则表达式模式:

static String testData = "0001,48;0451,0605\\,230001;0461,0606\\;230006;0431,0605230002";

并打印到以下组:

Group 1: 0001,48;
Group 2: 0451,0605\\,230001;
Group 3: 0461,0606\\;230006;
Group 4: 0431,0605230002;

我目前的模式在解析 '0605\,230001' 中出现的转义序列时效率不高。

static String testPattern = "([\\d]{4}" + "[,]{1}"+ "(?:[[a-zA-Z0-9][\\;][\\,][\\(][\\)][\\s]]*)"+ "[;]{1})" ;

上述模式仅在打印时有效:

Group 1: 0001,48;
Group 2: 0431,0605230001;

其余代码:

Pattern pattern=Pattern.compile(testPattern);
Matcher matcher = pattern.matcher(testData);

System.out.println("Test Matches: "+testData.matches(testPattern));

while(matcher.find())
{
    for (int i = 1; i <= matcher.groupCount(); i++) 
    {
        System.out.println("Group " + i + ": " + matcher.group(i));
    }
}

有没有办法让我们在模式中包含转义序列,并且在我们需要的时候也不转义它们?

【问题讨论】:

  • 你为什么使用正则表达式来做到这一点?看起来你只是想分开;
  • 如果@PeterMichealLacey-Bordeaux 正确,只需将所有“其他”分隔符替换为;
  • 当有'/;'时会发生什么,即';'前面有一个转义字符,它是否足够聪明地检测到转义字符并在拆分时忽略它?
  • @Fardu 在这种情况下使用正则表达式进行拆分
  • 我刚刚编辑了输入数据,因为可能会出现很多转义序列。

标签: java regex


【解决方案1】:

按照建议。您可以使用String#split() 方法使用正则表达式进行拆分。

在此处查看此示例:

String testData = "0001,48;0451,0605\\,230001;0431,0605230002;";
String[] array = testData.split("(?<=[^\\]);");
for(int i = 0; i < array.length; i++)
{
    System.out.println(array[i]);
}

打印出来的

"0001,48"
"0451,0605\\,230001"
"0431,0605230002"

然后,如果您的 testData 为 ""0001,48;0451,0605\\;230001;0431,0605230002;"(注意转义的 ;),它会打印

"0001,48"
"0451,0605\\;230001"
"0431,0605230002"

如果您最后需要分号,您可以手动添加它们或使用此正则表达式,它将保留分号并仅拆分非转义分号

"(?<=(?<=[^\\]);)"

【讨论】:

  • 请注意,如果输入被严重转义,正则表达式无法检测和拆分错误。
  • 感谢 Java Devil 的快速响应,我仍然会针对我的特定场景处理拆分正则表达式。
  • @nhahtdh 我不明白你的意思...示例?
  • 例如看我的帖子。不过,我不知道 OP 是否必须处理此类输入。
【解决方案2】:

当您想将输入拆分为由; 分隔的部分时,此模式应该可以工作:

"\\G([^;\\\\]|\\\\.)+;"

上面的正则表达式应该与Matcher.find()一起使用。需要注意的是,每次匹配后都需要记录是否已经到达输入的末尾,以便检查是否所有的输入都被消耗掉了。

这应该适用于严重转义的输入(注意这是文本,而不是 Java 字符串文字):

456\\\;734;82734\\\\;574\;347;

(作为 Java 字符串文字:"456\\\\\\;734;82734\\\\\\\\;574\\;347;"

将分为:

456\\\;734;
82734\\\\;
574\;347;

如果;前面有偶数个\,则表示\自行转义,所以;不会被转义。

【讨论】:

  • IMO 您的示例拆分不正确。第三个; 仍被转义,不应拆分...
  • @JavaDevil:第三个有偶数个\(注意这是原始字符串)。 Java 字符串字面量是“准备测试”版本。
  • 啊,是的,我现在明白了。是的,在这种情况下,我的正则表达式会失败......但正如你所说,取决于 OP 是否必须处理这种可能性。
【解决方案3】:

试试代码

for(String str : testData.split("(?<=(?<!\\\\);)"))
{
    System.out.println(str);
}

它使用 String 的 .split() 方法将字符串拆分为单独的部分,然后打印出每个部分。

如果您需要按照问题中的方式实现正则表达式,请将此字符串用于正则表达式:

"+*?(?<=(?<!\\\\);)"

在这里解释和演示:http://regex101.com/r/vW0oT9

【讨论】:

    【解决方案4】:

    采用my answer 的副本来回答另一个问题。

    虽然实现您自己的 split() 函数一开始可能看起来像是开销,但我的解决方案可以正确处理包含反斜杠转义分号和反斜杠之类的字符串

    String input = "0001,48;0451,0605\\,230001\\\\;0461,0606\\;230006;0431,0605230002";
    

    示例用法:

    import java.util.ArrayList;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class Print {
        public static void main(final String[] args) {
            String input = "0001,48;0451,0605\\,230001\\\\;0461,0606\\;230006;0431,0605230002";
            final String[] strings = splitValues(input);
            System.out.print("\""+input+"\" => ");
            printQuoted(strings);
        }
    
        public static String[] splitValues(final String input) {
            final ArrayList<String> result = new ArrayList<String>();
            // (?:\\\\)* matches any number of \-pairs
            // (?<!\\) ensures that the \-pairs aren't preceded by a single \
            final Pattern pattern = Pattern.compile("(?<!\\\\)(?:\\\\\\\\)*;");
            final Matcher matcher = pattern.matcher(input);
            int previous = 0;
            while (matcher.find()) {
                result.add(input.substring(previous, matcher.end()));
                previous = matcher.end();
            }
            result.add(input.substring(previous, input.length()));
            return result.toArray(new String[result.size()]);
        }
    
        public static void printQuoted(final String[] strings) {
            if (strings.length > 0) {
                System.out.print("[\"");
                System.out.print(strings[0]);
                for(int i = 1; i < strings.length; i++) {
                    System.out.print("\", \"");
                    System.out.print(strings[i]);
                }
                System.out.println("\"]");
            } else {
                System.out.println("[]");
            }
        }
    }
    

    将打印

    "0001,48;0451,0605\,230001\\;0461,0606\;230006;0431,0605230002" => ["0001,48;", "0451,0605\,230001\\;", "0461,0606\;230006;", "0431,0605230002"]

    如果您不需要在 ; 前面转义反斜杠的能力比你应该对内置函数没问题,例如this answer.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多