Регулярное выражение для разделения на пробелы, кроме как в кавычках - PullRequest
66 голосов
/ 16 февраля 2009

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

Ожидаемый результат:

  1. Здесь
  2. есть
  3. моя строка
  4. он
  5. есть
  6. шесть матчей

Какой шаблон мне нужен? Также мне нужно указать какие-либо RegexOptions?

Ответы [ 11 ]

62 голосов
/ 16 февраля 2009

Опции не требуются

Regex:

\w+|"[\w\s]*"

C #:

Regex regex = new Regex(@"\w+|""[\w\s]*""");

Или, если вам нужно исключить "символы:

    Regex
        .Matches(input, @"(?<match>\w+)|\""(?<match>[\w\s]*)""")
        .Cast<Match>()
        .Select(m => m.Groups["match"].Value)
        .ToList()
        .ForEach(s => Console.WriteLine(s));
16 голосов
/ 08 апреля 2009

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

(?<=")\w[\w\s]*(?=")|\w+|"[\w\s]*"

Ввод: вот «моя строка», в ней «шесть совпадений»

Выход:

  1. Здесь
  2. есть
  3. "моя строка"
  4. он
  5. есть
  6. "шесть матчей"

К сожалению, это включает в себя цитаты. Если вместо этого вы используете следующее:

(("((?<token>.*?)(?<!\\)")|(?<token>[\w]+))(\s)*)

И явно захватить совпадения «токена» следующим образом:

    RegexOptions options = RegexOptions.None;
    Regex regex = new Regex( @"((""((?<token>.*?)(?<!\\)"")|(?<token>[\w]+))(\s)*)", options );
    string input = @"   Here is ""my string"" it has   "" six  matches""   ";
    var result = (from Match m in regex.Matches( input ) 
                  where m.Groups[ "token" ].Success
                  select m.Groups[ "token" ].Value).ToList();

    for ( int i = 0; i < result.Count(); i++ )
    {
        Debug.WriteLine( string.Format( "Token[{0}]: '{1}'", i, result[ i ] ) );
    }

Отладочный вывод:

Token[0]: 'Here'
Token[1]: 'is'
Token[2]: 'my string'
Token[3]: 'it'
Token[4]: 'has'
Token[5]: ' six  matches'
9 голосов
/ 20 декабря 2011

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

"the lib.lib" "another lib".lib

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

    /// <summary>
    /// Splits the string passed in by the delimiters passed in.
    /// Quoted sections are not split, and all tokens have whitespace
    /// trimmed from the start and end.
    public static List<string> split(string stringToSplit, params char[] delimiters)
    {
        List<string> results = new List<string>();

        bool inQuote = false;
        StringBuilder currentToken = new StringBuilder();
        for (int index = 0; index < stringToSplit.Length; ++index)
        {
            char currentCharacter = stringToSplit[index];
            if (currentCharacter == '"')
            {
                // When we see a ", we need to decide whether we are
                // at the start or send of a quoted section...
                inQuote = !inQuote;
            }
            else if (delimiters.Contains(currentCharacter) && inQuote == false)
            {
                // We've come to the end of a token, so we find the token,
                // trim it and add it to the collection of results...
                string result = currentToken.ToString().Trim();
                if (result != "") results.Add(result);

                // We start a new token...
                currentToken = new StringBuilder();
            }
            else
            {
                // We've got a 'normal' character, so we add it to
                // the curent token...
                currentToken.Append(currentCharacter);
            }
        }

        // We've come to the end of the string, so we add the last token...
        string lastResult = currentToken.ToString().Trim();
        if (lastResult != "") results.Add(lastResult);

        return results;
    }
7 голосов
/ 08 марта 2011

Я использовал ответ Бартека Сабата, но мне нужно было захватить больше, чем просто символы \ w в моих токенах. Чтобы решить эту проблему, я немного изменил его регулярное выражение, аналогично ответу Грзенио:

Regular Expression: (?<match>[^\s"]+)|(?<match>"[^"]*")

C# String:          (?<match>[^\\s\"]+)|(?<match>\"[^\"]*\")

Код Бартека (который возвращает токены без заключенных в кавычки) становится:

Regex
        .Matches(input, "(?<match>[^\\s\"]+)|(?<match>\"[^\"]*\")")
        .Cast<Match>()
        .Select(m => m.Groups["match"].Value)
        .ToList()
        .ForEach(s => Console.WriteLine(s));
5 голосов
/ 15 февраля 2013

Я нашел регулярное выражение в этом ответе весьма полезным. Чтобы он работал в C #, вам нужно использовать класс MatchCollection.

//need to escape \s
string pattern = "[^\\s\"']+|\"([^\"]*)\"|'([^']*)'";

MatchCollection parsedStrings = Regex.Matches(line, pattern);

for (int i = 0; i < parsedStrings.Count; i++)
{
    //print parsed strings
    Console.Write(parsedStrings[i].Value + " ");
}
Console.WriteLine();
4 голосов
/ 16 февраля 2009

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

"[^"]+"|\s?\w+?\s
2 голосов
/ 16 февраля 2009

С небольшим количеством беспорядка, обычные языки могут отслеживать четное / нечетное подсчет кавычек, но если ваши данные могут включать в себя экранированные кавычки (\ "), тогда у вас есть реальная проблема с производством или пониманием регулярного выражения, которое будет справиться с этим правильно.

1 голос
/ 16 февраля 2009

Shaun

Я считаю, что следующее регулярное выражение должно сделать это

(?<=")\w[\w\s]*(?=")|\w+  

С уважением,
Ливны

1 голос
/ 16 февраля 2009

РЕДАКТИРОВАТЬ: Извините за мой предыдущий пост, это, очевидно, возможно.

Для обработки всех не алфавитно-цифровых символов вам нужно что-то вроде этого:

MatchCollection matchCollection = Regex.Matches(input, @"(?<match>[^""\s]+)|\""(?<match>[^""]*)""");
foreach (Match match in matchCollection)
        {
            yield return match.Groups["match"].Value;
        }

вы можете сделать foreach умнее, если используете .Net> 2.0

0 голосов
/ 26 июля 2010

Если вы хотите взглянуть на общее решение этой проблемы в виде бесплатного объекта с открытым исходным кодом javascript, вы можете посетить http://splitterjsobj.sourceforge.net/ для демонстрации (и загрузки). Объект имеет следующие особенности:

  • Пары определяемых пользователем символов кавычек могут использоваться для экранирования (не допускайте разбиения внутри кавычек). Кавычки могут быть экранированы с помощью пользовательского escape-символа и / или "двойным кавычкой". Экранирующая буква может быть экранирована (сама с собой). В одном из 5 выходных массивов (свойств объекта) выход не экранирован. (Например, если escape-символ = /, "a ///" b "не экранируется как a /" b)
  • Разделить на массив разделителей; разбирать файл за один звонок. (Выходные массивы будут вложенными.)
  • Все escape-последовательности, распознаваемые JavaScript, могут быть оценены во время процесса разделения и / или в предварительном процессе.
  • Функция обратного вызова
  • Кросс-браузерная согласованность

Объект также доступен в виде плагина jQuery, но как новый пользователь на этом сайте я могу включить только одну ссылку в это сообщение.

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