Регулярные выражения, соответствующие пробелам, но не в строках - PullRequest
4 голосов
/ 21 августа 2009

Я ищу регулярные выражения, соответствующие пробелам, только если эти пробелы не заключены в двойные кавычки ("). Например, в

Mary had "a little lamb"

должно совпадать с первым и вторым пробелом, но не с остальными.

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

Я использую C ++ с инструментарием Qt и хотел использовать QString :: split (QRegExp). QString очень похож на std :: string, а QRegExp в основном являются регулярным выражением POSIX, инкапсулированным в класс. Если бы существовало такое регулярное выражение, разбиение было бы тривиальным.

Примеры:

Mary had "a little lamb"     =>   Mary,had,"a little lamb"
1" 2 "3                      =>   1" 2 "3 (no splitting at ")
abc def="g h i" "j k" = 12   =>   abc,def="g h i","j k",=,12

Извините за правки, я был очень неточен, когда впервые задал вопрос. Надеюсь, теперь это несколько яснее.

Ответы [ 5 ]

7 голосов
/ 21 августа 2009

(Я знаю, что вы только что отправили почти точно такой же ответ сами, но я не могу просто выбросить все это.: - /)

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

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

Если текст правильно сформирован, достаточно заглянуть в четное число кавычек, чтобы определить, что только что найденное пространство не находится внутри последовательности в кавычках. То есть смотреть в глаза не нужно, и это хорошо, потому что QRegExp, кажется, не поддерживает их. Экранированные кавычки тоже можно разместить, но регулярное выражение становится немного больше и уродливее. Но если вы не уверены, что текст правильно сформирован, крайне маловероятно, что вы сможете решить свою проблему с помощью split().

Между прочим, QRegExp не реализует регулярные выражения POSIX - если бы он это сделал, он не поддерживал предпросмотры ИЛИ видоискатели. Вместо этого он попадает в свободно определенную категорию Perl-совместимых регулярных выражений.

4 голосов
/ 21 августа 2009

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

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

' (?=[^"]*("[^"]*"[^"]*)*$)'

В источнике это наконец выглядело (с использованием Qt и C ++)

QString buf("Mary had \"a little lamb\""); // string we want to split
QStringList splitted = buf.split( QRegExp(" (?=[^\"]*(\"[^\"]*\"[^\"]*)*$)") );

Простой, а?

Для исполнения строки разбираются один раз в начале программы, их несколько десятков и меньше ста символов. Я проверю его время выполнения с длинными строками, просто чтобы убедиться, что ничего плохого не случится; -)

4 голосов
/ 21 августа 2009

Что должно случиться с "a" b "c"?

Обратите внимание, что в подстроке " b " пробелы находятся между кавычками.

- редактировать -

Я предполагаю, что пробел находится "между кавычками", если ему предшествует нечетное количество стандартных кавычек (то есть U + 0022, я проигнорирую эти забавные "кавычки" Юникода).

Это означает, что вам нужно следующее регулярное выражение: ^[^"]*("[^"]*"[^"]*)*"[^"]* [^"]*"[^"]*("[^"]*"[^"]*)*$

("[^"]*"[^"]*) представляет пару кавычек. ("[^"]*"[^"]*)* - четное количество кавычек, ("[^"]"[^"]*)*" - нечетное количество. Затем есть фактическая часть строки в кавычках, за которой следует другое нечетное количество кавычек. ^$ якоря нужны, потому что вам нужно посчитать каждую кавычку с начала строки. Это решает проблему с подстрокой " b " выше, никогда не просматривая подстроки. Цена заключается в том, что каждый символ в вашем входе должен сопоставляться со всей строкой, что превращает это в операцию разделения O (N * N).

Причина, по которой вы можете сделать это в регулярном выражении, заключается в том, что требуется ограниченный объем памяти. Эффективно только один бит; «Я видел нечетное или четное количество цитат до сих пор?». На самом деле вам не нужно сопоставлять отдельные пары "".

Однако это не единственная возможная интерпретация. Если вы включаете “funny Unicode quotes”, который должен быть в паре, вам также нужно иметь дело с ““double quoted”” строками. Это, в свою очередь, означает, что вам нужно количество открытых , что означает, что вам нужно бесконечное хранилище, что, в свою очередь, означает, что это больше не обычный язык, что означает, что вы не можете использовать регулярное выражение. QED.

В любом случае, даже если бы это было возможно, вы все равно хотели бы иметь правильный анализатор. Поведение O (N * N) для подсчета количества кавычек, предшествующих каждому символу, просто не смешно. Если вы уже знаете, что перед Str [N] есть X кавычек, то для определения количества кавычек, предшествующих Str [N + 1], нужно указать O (1), а не O (N). Возможные ответы, в конце концов, просто X или X + 1!

1 голос
/ 21 августа 2009

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

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

В Perl, если вы используете группировку в регулярном выражении при вызове split(), функция возвращает не только элементы, но и захваченные группы (в данном случае наш разделитель). Если вы затем отфильтруете пробелы и разделители только для пробелов, вы получите требуемый список элементов. Я не знаю, будет ли подобная стратегия работать в C ++, но работает следующий код Perl:

use strict;
use warnings;
while (<DATA>){
    chomp;
    my @elements = split /(\"[^\"]*\"| +)/, $_;
    @elements = grep {length and /[^ ]/} @elements;
    # Do stuff with @elements
}

__DATA__
Mary had "a little lamb"
1" 2 "3
abc def="g h i" "j k" = 12
0 голосов
/ 21 августа 2009

Самое простое регулярное выражение: сопоставление целых пробелов и кавычек. Фильтр цитат позже

"[^"]*"|\s
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...