Разделение строки (особенно в Java с java.util.regex или чем-то еще) - PullRequest
1 голос
/ 07 мая 2009

Кто-нибудь знает, как разбить строку на символ с учетом его escape-последовательности?

Например, если символ «:», «a: b» разделяется на две части («a» и «b»), тогда как «a: b» вообще не разделяется.

Я думаю, что это трудно (невозможно?) Сделать с регулярными выражениями.

Заранее спасибо,

Кедар

Ответы [ 2 ]

2 голосов
/ 07 мая 2009

Поскольку Java поддерживает предварительные просмотры переменной длины (если они конечны), вы можете сделать это следующим образом:

import java.util.regex.*;

public class RegexTest {
    public static void main(String[] argv) {

        Pattern p = Pattern.compile("(?<=(?<!\\\\)(?:\\\\\\\\){0,10}):");

        String text = "foo:bar\\:baz\\\\:qux\\\\\\:quux\\\\\\\\:corge";

        String[] parts = p.split(text);

        System.out.printf("Input string: %s\n", text);
        for (int i = 0; i < parts.length; i++) {
            System.out.printf("Part %d: %s\n", i+1, parts[i]);
        }

    }
}
  • (?<=(?<!\\)(?:\\\\){0,10}) обеспечивает четное количество обратных косых черт (включая ноль, максимум до 10).

Выход:

Input string: foo:bar\:baz\\:qux\\\:quux\\\\:corge
Part 1: foo
Part 2: bar\:baz\\
Part 3: qux\\\:quux\\\\
Part 4: corge

Другим способом было бы сопоставление самих частей вместо разделения на разделители.

Pattern p2 = Pattern.compile("(?<=\\A|\\G:)((?:\\\\.|[^:\\\\])*)");
List<String> parts2 = new LinkedList<String>();
Matcher m = p2.matcher(text);
while (m.find()) {
    parts2.add(m.group(1));
}

Странный синтаксис проистекает из того, что он должен обрабатывать случай пустых частей в начале и конце строки. Когда совпадение охватывает ровно ноль символов, следующая попытка начнется через один символ после его окончания. Если этого не произойдет, он будет соответствовать другой пустой строке и другой, ad infinitum & hellip;

  • (?<=\A|\G:) будет искать либо начало строки (первый фрагмент), либо конец предыдущего совпадения, за которым следует разделитель. Если бы мы сделали (?:\A|\G:), он потерпел бы неудачу, если первый фрагмент пуст (ввод начинается с разделителя).
  • \\. соответствует любому экранированному символу.
  • [^:\\] соответствует любому символу, который не находится в escape-последовательности (потому что \\. использовал оба из них).
  • ((?:\\.|[^:\\])*) захватывает всех персонажей вплоть до первого неэкранированного разделителя в группу захвата 1.
2 голосов
/ 07 мая 2009

(?<=^|[^\\]): приближает вас, но не решает косые черты. (Это буквальное регулярное выражение, конечно, вы должны избегать косых черт в нем, чтобы вставить его в строку Java)

(?<=(^|[^\\])(\\\\)*): Как насчет этого? Я думаю, что это должно удовлетворять любому ':', которому предшествует четное число косых черт.

Редактировать: не голосуйте за это. Решение MizardX лучше:)

...