Java регулярное выражение разделить строку - PullRequest
6 голосов
/ 30 июля 2011

Я застрял, пытаясь придумать регулярное выражение, чтобы разбить строки со следующими свойствами:

  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 Ответ

13 голосов
/ 30 июля 2011

Хитрость в том, чтобы не использовать метод split().Это заставляет вас использовать вид сзади, чтобы обнаружить сбежавших персонажей, но не получается, когда сами сбежавшие сбежали (как вы обнаружили).Вместо него необходимо использовать find(), чтобы сопоставить токены вместо разделителей:

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

output:

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

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

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

One\\\|Two
[One\|Two]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...