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

Я новичок в регулярных выражениях и буду благодарен за вашу помощь. Я пытаюсь собрать выражение, которое разделит строку примера, используя все пробелы, которые не окружены одинарными или двойными кавычками. Моя последняя попытка выглядит так: (?!") и не совсем работает. Он разбивается на пробел перед цитатой.

Пример ввода:

This is a string that "will be" highlighted when your 'regular expression' matches something.

Требуемый вывод:

This
is
a
string
that
will be
highlighted
when
your
regular expression
matches
something.

Обратите внимание, что "will be" и 'regular expression' сохраняют пробел между словами.

Ответ 1

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

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

Я добавил группы захвата, потому что вам не нужны кавычки в списке.

Этот код Java строит список, добавляя группу захвата, если он соответствует исключению кавычек, и добавляет общее соответствие регулярному выражению, если группа захвата не соответствует (сопоставлено несогласованное слово).

List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
    if (regexMatcher.group(1) != null) {
        // Add double-quoted string without the quotes
        matchList.add(regexMatcher.group(1));
    } else if (regexMatcher.group(2) != null) {
        // Add single-quoted string without the quotes
        matchList.add(regexMatcher.group(2));
    } else {
        // Add unquoted word
        matchList.add(regexMatcher.group());
    }
} 

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

List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
    matchList.add(regexMatcher.group());
} 

Ответ 2

В StackOverflow есть несколько вопросов, которые охватывают этот же вопрос в различных контекстах, используя регулярные выражения. Например:

UPDATE. Образное регулярное выражение для обработки одиночных и двойных кавычек. Ссылка: Как я могу разделить на строку, кроме как внутри кавычек?

m/('.*?'|".*?"|\S+)/g 

Протестировано с помощью быстрого фрагмента Perl, и результат был воспроизведен ниже. Также работает для пустых строк или строк только в виде пробелов, если они находятся между кавычками (не уверены, что это желательно или нет).

This
is
a
string
that
"will be"
highlighted
when
your
'regular expression'
matches
something.

Обратите внимание, что это включает в себя сами символы кавычек в согласованных значениях, хотя вы можете удалить это с заменой строки или изменить регулярное выражение, чтобы не включать их. Я оставлю это как упражнение для читателя или другого плаката на данный момент, так как 2am слишком поздно, чтобы больше не возиться с регулярными выражениями;)

Ответ 3

Если вы хотите разрешить экранированные кавычки внутри строки, вы можете использовать что-то вроде этого:

(?:(['"])(.*?)(?<!\\)(?>\\\\)*\1|([^\s]+))

Строки в кавычках будут группой 2, одиночные слова без кавычек будут группой 3.

Вы можете попробовать его на различных строках здесь: http://www.fileformat.info/tool/regex.htm или http://gskinner.com/RegExr/

Ответ 4

Регулярное выражение от Jan Goyvaerts - лучшее решение, которое я нашел до сих пор, но создает также пустые (нулевые) совпадения, которые он исключает в своей программе. Эти пустые совпадения также отображаются в тестерах regex (например, rubular.com). Если вы включите поиск arround (сначала найдите цитированные части и слова, разделенные пробелами), вы можете сделать это один раз с помощью:

("[^"]*"|'[^']*'|[\S]+)+

Ответ 5

(?<!\G".{0,99999})\s|(?<=\G".{0,99999}")\s

Это будет соответствовать пробелам, не окруженным двойными кавычками. Мне нужно использовать min, max {0,99999}, потому что Java не поддерживает * и + в lookbehind.

Ответ 6

Скорее всего, будет проще искать строку, захватывая каждую часть, и разделяя ее.

Признавая, что вы можете разбить его на пробелы до и после "will be". Но я не могу придумать, как можно указать игнорирование пространства между разделом.

(не действительная Java)

string = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";

regex = "\"(\\\"|(?!\\\").)+\"|[^ ]+"; // search for a quoted or non-spaced group
final = new Array();

while (string.length > 0) {
    string = string.trim();
    if (Regex(regex).test(string)) {
        final.push(Regex(regex).match(string)[0]);
        string = string.replace(regex, ""); // progress to next "word"
    }
}

Кроме того, захват одиночных кавычек может привести к проблемам:

"Foo Bar 'n Grill"

//=>

"Foo"
"s Bar "
"n"
"Grill"

Ответ 7

String.split() здесь не помогает, потому что нет возможности различать пробелы внутри кавычек (не разделять) и внешние (разделенные). Matcher.lookingAt(), вероятно, вам нужно:

String str = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";
str = str + " "; // add trailing space
int len = str.length();
Matcher m = Pattern.compile("((\"[^\"]+?\")|('[^']+?')|([^\\s]+?))\\s++").matcher(str);

for (int i = 0; i < len; i++)
{
    m.region(i, len);

    if (m.lookingAt())
    {
        String s = m.group(1);

        if ((s.startsWith("\"") && s.endsWith("\"")) ||
            (s.startsWith("'") && s.endsWith("'")))
        {
            s = s.substring(1, s.length() - 1);
        }

        System.out.println(i + ": \"" + s + "\"");
        i += (m.group(0).length() - 1);
    }
}

который производит следующий вывод:

0: "This"
5: "is"
8: "a"
10: "string"
17: "that"
22: "will be"
32: "highlighted"
44: "when"
49: "your"
54: "regular expression"
75: "matches"
83: "something."

Ответ 8

Мне понравился подход Маркуса, однако я изменил его так, чтобы я мог разрешить текст рядом с кавычками и поддерживать оба символа "и". Например, мне нужно было = "некоторое значение", чтобы не разбить его на [a =, "некоторое значение" ].

(?<!\\G\\S{0,99999}[\"'].{0,99999})\\s|(?<=\\G\\S{0,99999}\".{0,99999}\"\\S{0,99999})\\s|(?<=\\G\\S{0,99999}'.{0,99999}'\\S{0,99999})\\s"

Ответ 9

Ян подход большой, но здесь еще один для записи.

Если вы действительно хотели разделить, как указано в заголовке, сохраняя кавычки в "will be" и 'regular expression', вы можете использовать этот метод, который прямо из Match ( или заменить) шаблон, за исключением ситуаций s1, s2, s3 и т.д.

Регулярное выражение:

'[^']*'|\"[^\"]*\"|( )

Два левых чередования соответствуют полному 'quoted strings' и "double-quoted strings". Мы проигнорируем эти матчи. Правая сторона сопоставляет и фиксирует пробелы в группе 1, и мы знаем, что они являются правильными пространствами, потому что они не соответствовали выражениям слева. Мы заменяем те с SplitHere, а затем разделяем на SplitHere. Опять же, это для истинного раздельного случая, где вы хотите "will be", а не will be.

Ниже приведена полная рабочая реализация (см. результаты в онлайн-демонстрация).

import java.util.*;
import java.io.*;
import java.util.regex.*;
import java.util.List;

class Program {
public static void main (String[] args) throws java.lang.Exception  {

String subject = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";
Pattern regex = Pattern.compile("\'[^']*'|\"[^\"]*\"|( )");
Matcher m = regex.matcher(subject);
StringBuffer b= new StringBuffer();
while (m.find()) {
    if(m.group(1) != null) m.appendReplacement(b, "SplitHere");
    else m.appendReplacement(b, m.group(0));
}
m.appendTail(b);
String replaced = b.toString();
String[] splits = replaced.split("SplitHere");
for (String split : splits) System.out.println(split);
} // end main
} // end Program

Ответ 10

Если вы используете С#, вы можете использовать

string input= "This is a string that \"will be\" highlighted when your 'regular expression' matches <something random>";

List<string> list1 = 
                Regex.Matches(input, @"(?<match>\w+)|\""(?<match>[\w\s]*)""|'(?<match>[\w\s]*)'|<(?<match>[\w\s]*)>").Cast<Match>().Select(m => m.Groups["match"].Value).ToList();

foreach(var v in list1)
   Console.WriteLine(v);

Я специально добавил " | < (? [\ w\s] *) > ", чтобы подчеркнуть, что вы можете указать любой char для группировки фраз. (В этом случае я использую < > для группировки.

Выход:

This
is
a
string
that
will be
highlighted
when
your
regular expression 
matches
something random

Ответ 11

Я уверен, что это невозможно, используя только регулярные выражения. Проверка того, что что-то содержится внутри какого-либо другого тега, - это операция синтаксического анализа. Это похоже на ту же проблему, что и попытка разобрать XML с помощью регулярного выражения - это невозможно сделать правильно. Вы можете получить желаемый результат, повторно применяя не-жадное, неглобальное регулярное выражение, которое соответствует цитируемым строкам, а затем, когда вы не можете найти что-либо еще, разделите его на пробелы..., в котором есть несколько проблемы, в том числе отслеживание первоначального порядка всех подстрок. Лучше всего написать просто простую функцию, которая выполняет итерацию по строке и вытаскивает нужные вам жетоны.

Ответ 12

Пару надеемся, что полезные рекомендации по принятому Ян ответят:

(['"])((?:\\\1|.)+?)\1|([^\s"']+)
  • Позволяет скрытые кавычки в цитированных строках
  • Избегает повторения шаблона для одиночной и двойной кавычек; это также упрощает добавление дополнительных котировочных символов, если необходимо (за счет еще одной группы захвата).

Ответ 13

Вы также можете попробовать следующее:

    String str = "This is a string that \"will be\" highlighted when your 'regular expression' matches something";
    String ss[] = str.split("\"|\'");
    for (int i = 0; i < ss.length; i++) {
        if ((i % 2) == 0) {//even
            String[] part1 = ss[i].split(" ");
            for (String pp1 : part1) {
                System.out.println("" + pp1);
            }
        } else {//odd
            System.out.println("" + ss[i]);
        }
    }

Ответ 14

Следующее возвращает массив аргументов. Аргументы - это переменная 'command', разделенная пробелами, если она не включена в одинарные или двойные кавычки. Затем совпадения модифицируются для удаления одинарных и двойных кавычек.

using System.Text.RegularExpressions;

var args = Regex.Matches(command, "[^\\s\"']+|\"([^\"]*)\"|'([^']*)'").Cast<Match>
().Select(iMatch => iMatch.Value.Replace("\"", "").Replace("'", "")).ToArray();