2013-10-11 2 views
5

Я пишу приложение, которое считывает некоторые данные из простого текстового файла. Файлы данных, что я заинтересован в, есть строки в следующем виде:Регулярное выражение для анализа данных

Mem(100) = 120 
Mem(200) = 231 
Mem(43) = 12 
... 
Mem(1293) = 12.54 

Итак, как вы можете понять, образец каждой линии что-то вроде

(\s)*(\t)*Mem([0-9]*) (\s,\t)*= (\s,\t)*[0-9]*(.)*[0-9]* 

как у меня есть любое количество пробелов перед символьной последовательностью «Mem», а затем - левая скобка. Тогда есть число и правая скобка. Впоследствии существует любое количество белых пробелов, пока не встретится символ «=» (равно). Затем любое количество белых пробелов, пока я не натолкнулся (возможно) число с плавающей запятой.

Как я могу выразить это в шаблоне регулярного выражения C++? Я действительно новичок в концепции регулярного выражения на C++, поэтому мне нужна помощь.

Спасибо

+0

Я не совсем понимаю вопрос. Если вы хотите знать, как использовать регулярное выражение на C++, есть много примеров. Кстати, вам, вероятно, следует избегать ваших скобок - '... Mem \ ([0-9] * \) ...'. – Dukeling

+0

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

+1

Регулярные выражения являются излишними для такого простого шаблона. Прочитайте строку в строке, ищите '(', search ')', ищите следующую цифру. –

ответ

15

Прежде всего, помните, чтобы #include <regex>.

C++ std::regex_match работает как регулярные выражения на других языках. начало

Давайте на простом примере:

std::string str = "Mem(100)=120"; 
std::regex regex("^Mem\\([0-9]+\\)=[0-9]+$"); 
std::cout << std::regex_match(str, regex) << std::endl; 

В этом случае наше регулярное выражение ^Mem\([0-9]+\)=[0-9]+$. Давайте посмотрим на то, что он делает:

  • ^ в начале говорит C++ это, где начинается линия, поэтому AMem(1)=2 не должны совпадать.
  • $ в конце говорит C++, где заканчивается линия, поэтому Mem(1)=2x не должен совпадать.
  • \\( - буква ( персонаж. ( имеет особое значение в регулярных выражениях, поэтому мы избегаем его \(. Однако символ \ имеет особое значение в строках C++, поэтому мы используем \\(, чтобы сообщить C++ передать \( в механизм регулярных выражений.
  • [0-9] соответствует цифре. \\d также должен работать, но then again maybe not.
  • [0-9]+ означает как минимум один разряд. Если Mem() является приемлемым, используйте вместо этого [0-9]*.

Как вы можете видеть, это похоже на регулярные выражения, которые вы найдете на других языках (например, Java или C#).

Теперь, чтобы рассмотреть пробелы, используйте std::regex regex("^\\s*Mem\\([0-9]+\\)\\s*=\\s*[0-9]+\\s*$");

Обратите внимание, что \s не включает \t, поэтому нет необходимости указывать оба. Если это не так, вы должны использовать (\s|\t) или [\s\t], а не (\s,\t).

И, наконец, чтобы включить номера с плавающей запятой, сначала нужно подумать, допустимо ли Mem(1) = 1. (т. Е. Точка без номера после него).

Если это не так, то .23 в 1.23 является факультативно. В regexes мы используем ?, чтобы указать это.

std::regex regex("^[\\s]*Mem\\([0-9]+\\)\\s*=\\s*[0-9]+(\\.[0-9]+)?\\s*$"); 

Обратите внимание, что мы используем \. вместо лишь .. . имеет особое значение в регулярных выражениях - он соответствует любому символу, поэтому нам нужно его избежать.

Если у вас есть компилятор, который поддерживает исходные строки (например, Visual Studio 2013, GCC 4.5, Clang 3.0), можно упростить регулярное выражение строки:

std::regex regex(R"(^[\s]*Mem\([0-9]+\)\s*=\s*[0-9]+(\.[0-9]+)?\s*$)") 

Для извлечения информации о найденной строке, вы можете использовать std::smatch и группы. начало

Давайте с небольшим изменением:

std::string str = " Mem(100)=120"; 
std::regex regex("^[\\s]*Mem\\(([0-9]+)\\)\\s*=\\s*([0-9]+(\\.[0-9]+)?)\\s*$"); 
std::smatch m; 

std::cout << std::regex_match(str, m, regex) << std::endl; 

Примечание три вещи:

  1. Мы добавили smatch. Этот класс хранит дополнительную информацию о результатах матча.
  2. Мы добавили дополнительные скобки вокруг [0-9]*. Это определяет группу. Группы сообщают движку регулярных выражений отслеживать все, что находится внутри них.
  3. Еще скобки вокруг числа с плавающей запятой. Это определяет вторую группу.

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

Теперь у нас есть группы, мы можем использовать их:

for (auto result : m) { 
    std::cout << result << std::endl; 
} 

Это первый печать всю строку, то число в Mem(), то окончательное число.

Другими словами, m[0] дает нам весь матч, m[1] дает нам первую группу, m[2] дает нам вторую группу и m[3] даст нам третью группу, если у нас была одна.

+3

Вы также можете использовать необработанные строковые литералы, чтобы избавиться от escape-последовательностей.'R" regex (hello \ world) regex "' – dyp

+1

@DyP Да, поскольку 'regex' - это C++ 11, в любом случае, должны быть доступны строковые литералы *. К сожалению, некоторые реализации C++, такие как Visual Studio, которые поддерживают регулярные выражения, не поддерживают исходные строковые литералы. – luiscubal

+0

@luiscubal Большое спасибо за ваш ответ. Это очень помогло мне. Моим последующим вопросом было бы, как захватить число внутри двух скобок. Например, если у меня есть Mem (Num), как я могу выделить строку Num? –

Смежные вопросы