Извлечение значений в кавычках и без кавычек с использованием регулярных выражений

Я пытаюсь проанализировать строку типа <tag>=<value> с помощью регулярных выражений, но столкнулся с некоторыми проблемами, добавляя поддержку значений в кавычках. Идея состоит в том, что любые значения без кавычек должны быть обрезаны начальными/конечными пробелами, чтобы [ Hello ] стало [Hello] (пожалуйста, игнорируйте квадратные скобки).

Однако, когда значение указано в кавычках, я хочу, чтобы все, вплоть до двойных кавычек, было удалено, но не дальше, поэтому [ " Hello World " ] станет [" Hello World "]

До сих пор я придумал следующий код с сопоставлением с образцом для этого (обратите внимание, что некоторые символы были экранированы или дважды экранированы, чтобы их не интерпретировали как триграфы или другие символы формата C).

void getTagVal( const std::string& tagVal )
{
    boost::smatch what;
    static const boost::regex pp("^\\s*([a-zA-Z0-9_-]+)\\s*=\\s*\"\?\?([%:\\a-zA-Z0-9 /\\._]+?)\"\?\?\\s*$");

    if ( boost::regex_match( tagVal, what, pp ) )
    {
        const string tag = static_cast<const string&>( what[1] );
        const string val = static_cast<const string&>( what[2] );

        cout << "Tag = [" << tag << "] Val = [" << val << "]" << endl;
    }
}

int main( int argc, char* argv[] )
{
    getTagVal("Qs1= \" Hello World \" ");
    getTagVal("Qs2=\" Hello World \" ");
    getTagVal("Qs3= \" Hello World \"");
    getTagVal("Qs4=\" Hello World \"");
    getTagVal("Qs5=\"Hello World \"");
    getTagVal("Qs6=\" Hello World\"");
    getTagVal("Qs7=\"Hello World\"");

    return 0;
}

Вынимая двойное экранирование, это разбивается на:

  • ^ - Начало строки.
  • \s* - необязательное количество пробелов.
  • ([a-zA-Z0-9_-]+) — один или несколько буквенно-цифровых символов, тире или подчеркивание. Это фиксируется как тег.
  • \s* - необязательное количество пробелов.
  • = - символ "равно".
  • \s* - необязательное количество пробелов.
  • "?? - необязательная двойная кавычка (не жадная).
  • ([%:\a-zA-Z0-9 /\._]+?) — один или несколько буквенно-цифровых символов или пробел, подчеркивание, процент, двоеточие, точка, косая черта вперед или назад. Это фиксируется как значение (не жадное).
  • "?? - необязательная двойная кавычка (не жадная).
  • \s* - необязательное количество пробелов.
  • $ - Конец строки

Для примеров вызовов в main() я ожидал бы получить:

Tag = [Qs1] Val = [ Hello World ]
Tag = [Qs2] Val = [ Hello World ]
Tag = [Qs3] Val = [ Hello World ]
Tag = [Qs4] Val = [ Hello World ]
Tag = [Qs5] Val = [Hello World ]
Tag = [Qs6] Val = [ Hello World]
Tag = [Qs7] Val = [Hello World]

но на самом деле я получаю:

Tag = [Qs1] Val = [" Hello World ]
Tag = [Qs2] Val = [" Hello World ]
Tag = [Qs3] Val = [" Hello World ]
Tag = [Qs4] Val = [" Hello World ]
Tag = [Qs5] Val = ["Hello World ]
Tag = [Qs6] Val = [" Hello World]
Tag = [Qs7] Val = ["Hello World]

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


person Component 10    schedule 18.01.2013    source источник
comment
покажите нам код, который вы используете для сопоставления текста   -  person Anirudha    schedule 18.01.2013
comment
@Some1.Kill.The.DJ: Должен быть там сейчас.   -  person Component 10    schedule 18.01.2013


Ответы (2)


Я бы изменил часть, начинающуюся с первой цитаты, на альтернативу:

"([^"]+)"|([%:\a-zA-Z0-9 /\._]+)\s*

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

person FrankPl    schedule 18.01.2013
comment
@FrankPi: Спасибо. Однако я думаю, что понял это. - person Component 10; 18.01.2013

Разобрался в чем проблема.

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

Итак, чтобы сказать, что я хочу, чтобы \ был в моем наборе символов в значении (что я и делаю по иронии судьбы, они используются как escape-последовательности в строке формата), тогда вам нужно дважды экранировать их, поэтому

static const boost::regex pp("^\\s*([a-zA-Z0-9_-]+)\\s*=\\s*\"\?\?([%:\\a-zA-Z0-9 /\\._]+?)\"\?\?\\s*$");

становится:

static const boost::regex pp("^\\s*([a-zA-Z0-9_-]+)\\s*=\\s*\"\?\?([%:\\\\a-zA-Z0-9 /._]+?)\"\?\?\\s*$");

(т.е. вам нужно сделать его \\\\)

person Component 10    schedule 18.01.2013