Java正则表达式分割字符串

6

我在试图编写正则表达式来分解具有以下特性的字符串时遇到了问题:

  1. 由 |(管道)字符分隔
  2. 如果单个值包含管道,则使用 \(反斜杠)进行转义
  3. 如果单个值以反斜杠结尾,则使用反斜杠进行转义

例如,以下是我想要分解的一些字符串:

  1. One|Two|Three 应返回: ["One", "Two", "Three"]
  2. One\|Two\|Three 应返回: ["One|Two|Three"]
  3. One\\|Two\|Three 应返回: ["One\", "Two|Three"]

那么如何使用单个正则表达式拆分它?

更新:正如许多人已经建议的那样,这不是正则表达式的好应用程序。此外,正则表达式解决方案比仅迭代字符慢几个数量级。我最终使用字符迭代。

public static List<String> splitValues(String val) {
    final List<String> list = new ArrayList<String>();
    boolean esc = false;
    final StringBuilder sb = new StringBuilder(1024);
    final CharacterIterator it = new StringCharacterIterator(val);
    for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
        if(esc) {
            sb.append(c);
            esc = false;
        } else if(c == '\\') {
            esc = true;
        } else if(c == '|') {
            list.add(sb.toString());
            sb.delete(0, sb.length());
        } else {
            sb.append(c);
        }
    }
    if(sb.length() > 0) {
        list.add(sb.toString());
    }
    return list;
}

1
让我们明确一下。你想要的是这样的:按 | 分割字符串并从中删除它,不要按 | 分割字符串并删除 \,最后按 \| 分割并从第一部分中删除 | 和从第二部分中删除 \。你认为如何用一个正则表达式实现?对我来说这似乎是完全不同的情况... - user219882
你能改变分隔符吗? - Paul
我认为你们是正确的!这可能对于正则表达式来说太多了。 - Mohamed Nuur
1个回答

13

关键在于不使用split()方法。这会强制您使用回顾后断言来检测转义字符,但如果转义被转义(如您所发现的那样),则会失败。相反,您需要使用find()来匹配tokens而不是分隔符:

public static List<String> splitIt(String source)
{
  Pattern p = Pattern.compile("(?:[^|\\\\]|\\\\.)+");
  Matcher m = p.matcher(source);
  List<String> result = new ArrayList<String>();
  while (m.find())
  {
    result.add(m.group().replaceAll("\\\\(.)", "$1"));
  }
  return result;
}

public static void main(String[] args) throws Exception
{
  String[] test = { "One|Two|Three", 
                    "One\\|Two\\|Three", 
                    "One\\\\|Two\\|Three", 
                    "One\\\\\\|Two" };
  for (String s :test)
  {
    System.out.printf("%n%s%n%s%n", s, splitIt(s));
  }
}

输出:

One|Two|Three
[One, Two, Three]

One\|Two\|Three
[One|Two|Three]

One\\|Two\|Three
[One\, Two|Three]

One\\\|Two
[One\|Two]

很厉害。你能解释一下这个模式是如何工作的吗?我仍然对正则表达式感到困惑。 - Paul
这个工作非常好!再次感谢 @Alan Moore!现在你要怎么做相反的呢? - Mohamed Nuur
1
@Paul:基本思路是,你永远不会匹配一个反斜杠而不消耗下一个字符。这样你就永远不会与转义序列失去同步。但如果你真的想理解正则表达式,你应该阅读《正则表达式必知必会》(The Book)。链接 - Alan Moore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接