Регулярное выражение для разделения строки с использованием пробела, если оно не окружено одинарными или двойными кавычками
Я новичок в регулярных выражениях и буду благодарен за вашу помощь. Я пытаюсь собрать выражение, которое разделит строку примера, используя все пробелы, которые не окружены одинарными или двойными кавычками. Моя последняя попытка выглядит так: (?!")
и не совсем работает. Он разбивается на пробел перед цитатой.
Пример ввода:
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();