2013-10-11 263 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

@Dukeeling,这就是我在这里问的原因。我既没有找到类似的例子,也没有弄清楚正则表达式模式匹配是如何工作的。 –

+1

正则表达式对于这样一个简单的模式是矫枉过正的。将行读入字符串,搜索'(',搜索')',搜索下一个数字。 –

回答

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可选。在正则表达式中,我们使用?来表示。

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

注意,我们使用\.,而不只是..在正则表达式中有特殊含义 - 它匹配任何字符 - 所以我们需要逃避它。

如果您有支持原始字符串编译器(如Visual Studio 2013GCC 4.5Clang 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

您也可以使用原始字符串文字来摆脱转义序列。'R“正则表达式(你好\世界)正则表达式”' – dyp

+1

@DyP是的,因为'正则表达式'是C++ 11无论如何,原始字符串*应该*可用。不幸的是,支持正则表达式的一些C++实现(如Visual Studio)不支持原始字符串文字。 – luiscubal

+0

@luiscubal非常感谢您的回答。它真的帮了我很多。我的后续问题将是如何抓住两个括号内的数字。就像我有Mem(Num)一样,我怎样才能隔离Num字符串? –