Регулярное выражение для выбора всех пробелов, которых нет в кавычках? - PullRequest
26 голосов
/ 06 марта 2012

Я не очень хорош в RegEx, может кто-нибудь дать мне регулярное выражение (для использования в Java), которое выберет все пробелы, которые не находятся между двумя кавычками? Я пытаюсь удалить все такие пробелы из строки, поэтому любое решение для этого будет работать.

Например:

(это тестовое "предложение для регулярного выражения")

должно стать

(это последнее "предложение для регулярного выражения")

Ответы [ 7 ]

39 голосов
/ 06 марта 2012

Вот одна замена-регулярное выражение, которая работает:

\s+(?=([^"]*"[^"]*")*[^"]*$)

который заменит:

(this is a test "sentence for the regex" foo bar)

с:

(thisisatest"sentence for the regex"foobar)

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

\s+(?=((\\[\\"]|[^\\"])*"(\\[\\"]|[^\\"])*")*(\\[\\"]|[^\\"])*$)

, который заменяет ввод:

(this is a test "sentence \"for the regex" foo bar)

с:

(thisisatest"sentence \"for the regex"foobar)

(обратите внимание, что он также работает с экранированными символами возврата: (thisisatest"sentence \\\"for the regex"foobar))

Само собой разумеется, (?), Это действительно не должно использоваться для выполнения такой задачи: у него кровоточат глаза, и оно выполняет свою задачу в квадратичном времени, в то время как существует простое линейное решение.

EDIT

Небольшая демонстрация:

String text = "(this is a test \"sentence \\\"for the regex\" foo bar)";
String regex = "\\s+(?=((\\\\[\\\\\"]|[^\\\\\"])*\"(\\\\[\\\\\"]|[^\\\\\"])*\")*(\\\\[\\\\\"]|[^\\\\\"])*$)";
System.out.println(text.replaceAll(regex, ""));

// output: (thisisatest"sentence \"for the regex"foobar)
10 голосов
/ 16 июля 2014

Вот регулярное выражение, которое работает для одинарных и двойных кавычек (при условии, что все строки разделены правильно)

\s+(?=(?:[^\'"]*[\'"][^\'"]*[\'"])*[^\'"]*$)

Не работает со строками, в которых есть кавычки.

Regular expression visualization

1 голос
/ 06 марта 2012

Если есть только один набор цитат, вы можете сделать это:

    String s = "(this is a test \"sentence for the regex\") a b c";

    Matcher matcher = Pattern.compile("^[^\"]+|[^\"]+$").matcher(s);
    while (matcher.find())
    {
        String group = matcher.group();
        s = s.replace(group, group.replaceAll("\\s", ""));
    }

    System.out.println(s); // (thisisatest"sentence for the regex")abc
1 голос
/ 06 марта 2012

Группы пробелов вне кавычек разделены тем, что а) не является пробелом, или б) внутри кавычек.

Возможно, что-то вроде:

(\s+)([^ "]+|"[^"]*")*

Первая часть соответствует последовательности пробелов; вторая часть соответствует непробелам (и не кавычкам), или некоторым вещам в кавычках, которые повторяются любое количество раз. Вторая часть - это разделитель.

Это даст вам две группы для каждого элемента в результате; просто игнорируйте второй элемент. (Нам нужны круглые скобки для точности, а не для группирования совпадений.) Или, можно сказать, объединить все вторые элементы - хотя вам также нужно сопоставить первое непробельное слово, или в этом примере сделайте пробелы необязательными:

StringBuffer b = new StringBuffer();
Pattern p = Pattern.compile("(\\s+)?([^ \"]+|\"[^\"]*\")*");
Matcher m = p.matcher("this is \"a test\"");
while (m.find()) {
    if (m.group(2) != null)
        b.append(m.group(2));
}
System.out.println(b.toString());

(Я не делал много регулярных выражений в Java, так что ожидайте ошибок.)

Наконец, вот как бы я это сделал, если бы регулярные выражения были обязательными. ; -)

Помимо техники Ксавье, вы можете просто сделать это так, как вы делали бы это в C: просто перебирать вводимые символы и копировать каждый в новую строку, если она не пробел, или вы посчитали нечетное количество кавычек до этой точки.

1 голос
/ 06 марта 2012

Это не то, что регулярные выражения хороши в.Функции поиска и замены с регулярными выражениями всегда немного ограничены, и любой вид вложения / ограничения вообще становится трудным и / или невозможным.

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

Надеюсь, это поможет!

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

PPS: Как только вы разберетесь со своими подстроками, , а затем самое время использовать регулярные выраженияубить эти пробелы - никаких кавычек, о которых стоит беспокоиться.Просто не забудьте использовать модификатор /.../g, чтобы убедиться, что это глобальная замена, а не только первое совпадение.

0 голосов
/ 18 января 2017

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

\s+(?=(?:'(?:\\'|[^'])+'|[^'])+$)

Он (в теории) работает с использованием совпадения, чтобы убедиться, что одинарные кавычки (') сбалансированы до конца строки перед проверкой, чтобы проверить, является ли пробел допустимым местом для разрыва.

Это изображение показывает, что оно выполняется и работает, но довольно медленно. Как могли бы заметить другие ответы, использование такого выражения для разделения строки, заключенной в кавычки, использует молоток для удаления заклепки. В моем случае я ввожу это регулярное выражение в программу, которая использует регулярное выражение для разделения (fzf).

0 голосов
/ 06 марта 2012

Это не точное решение, но вы можете достичь своей цели, выполнив следующие действия:

ШАГ 1: сопоставить два сегмента

\\(([a-zA-Z ]\*)"([a-zA-Z ]\*)"\\)

ШАГ 2: удалить пробелы

temp = $1 replace " " with ""

ШАГ 3: восстановите строку

(temp"$2")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...