Подтвердить что ты не робот

Регулярное выражение для выбора всех пробелов, которые не указаны в кавычках?

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

Например:

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

должен стать

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

4b9b3361

Ответ 1

Здесь выполняется одно регулярное выражение:

\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))

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

ИЗМЕНИТЬ

Быстрая демонстрация:

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)

Ответ 2

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

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

Он не будет работать со строками, в которых есть кавычки внутри.

Regular expression visualization

Ответ 3

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

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

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

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

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

Ответ 4

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

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

(\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, поэтому ожидаю ошибок.)

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

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

Ответ 5

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

    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

Ответ 6

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

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

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

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

temp = $1 replace " " with ""

ШАГ 3: перестройте свою строку

(temp"$2")

Ответ 7

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

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

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

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