2013-10-11 197 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字符串? –