2013-12-13 32 views
0

特殊括號串我有以下line字符串:如何分析在C++

(1,2,3); (3,4,5);(6,7,8); (9,10,11);

我想從第一個元組中提取數字1,2和3;第二個,第三個,第四個和第五個,等等。

我所做的到目前爲止是與此代碼我提取由分隔字符串「;」:

stringstream ss(line); 
string tuple; 
vector<string> tuples_vec; 
while (getline(ss, tuple, ';')) 
    tuples_vec.push_back(tuple); 

OK,所以我想我會在tuples_vec如下:

(1,2,3) 
(3,4,5) 
(6,7,8) 
(9,10,11) 

現在,我如何從中提取數字?請注意,可能存在可變數量的空白。

我認爲這部分的想法可能是刪除字符,直到第一個'('和倒退到第一個')'。然後,用「1,2,3」我想我可以做一個while(getline(ss, number, ',')),但我認爲有一個更簡單的方法。此外,我不知道如何編碼這部分(刪除字符)。

感謝,

+0

你聽說過'的std :: stoi'的? –

+0

@DanielDaranas我已經更新了我的想法,我的想法是那部分。 –

回答

1
std::string str; // input data 

std::stringstream ss; 
int x, y, z; 
char fake; 

ss << str; 
ss >> fake >> x >> fake >> y >> fake >> z >> fake; 

x, y, z; // output data 
+0

我喜歡這個答案,我會嘗試一下,看看它是怎麼回事... –

+0

你能向我解釋爲什麼'假'是'char'類型?我發現它從輸入中消耗了不止一個字符,所以對我來說這將是一個「字符串」(答案似乎有效,但我想知道爲什麼)。 –

+0

我們知道字符串的結構,它是「(數字,數字,數字)」。如果我們將它表示爲解析,它將是「char(括號)+ int(x)+ char(逗號)+ int(y)+ char(逗號)+ int(z)+ char(括號)」(忽略空格與默認標誌在流中)。 – x1Mike7x

2

既然你不狀態檢查輸入語法的有效性的要求,你可以做最簡單的就是

  • 替換爲每個「(」,「)」和「」空間。
  • 替換每個';'換行(這不是絕對必要的,但很簡單)。
  • 使用例如一次讀取一行。 std::getline,將其放在istringstream中,然後從流中一次讀取一個數字。

我覺得這樣做的方式是,通過代碼接受簡單的數字行,您可以通過鍵入它或類似的方法來嘗試它。並且還支持其他格式。

祝你好運。


PS:這是不是正則表達式的工作。 ;-)

+0

儘管如此,一個正則表達式可以快速完成這個簡單的事情。 –

2

首先,讓我們從一個Line類:

class Line 
{ 
    int a, b, c; 
}; 

我們需要重載的提取,這樣的格式化字符串可以解析:

template<class charT> 
friend basic_istream<charT>& operator>>(basic_istream<charT>& is, Line& line) 
{ 
    return is >> line.a >> line.b >> line.c; 
} 

但在爲了提取工作,流需要「忽略」重要數據周圍的字符。我們需要將流解析爲'(',',',')'和​​3210作爲空格字符。

流使用表查找char類型的對象。我們可以製作我們自己的表格:

class line_parser : public std::ctype<char> 
{ 
public: 
    static mask* make_table() 
    { 
     static std::vector<mask> v(classic_table(), 
            classic_table() + table_size); 
     int table[10] = {0x20, 0x0c, 0x0a, 0x0d, 0x09, 
         0x0b, '(', ',', ')', ';'}; 
     //      ^^^^^^^^^^^^^^^^^^ 

     for (int i : table) 
      v[i] |= space; 

     return &v[0]; 
    } 

    explicit line_parser(int refs = 0) : ctype(make_table(), false, refs) { } 
}; 

這是一個派生的類構面。我們可以像這樣將這個方面注入流中:

stringstream ss(line); 
ss.imbue(locale(ss.getloc(), new line_parser)); 

但是說實話,它有點乏味。用戶不僅需要在流中注入新的語言環境,而且如果他們稍後要使用以前的格式設置,他們還必須重新記錄原始語言環境。爲了促進這一點,我們必須找到一些封裝這個功能的方法。我們將創建一個機械手,這是否給我們:

template<class Line> 
class line_extractor 
{ 
public: 
    line_extractor(Line& other) 
     : line(other) 
    { } 
private: 
    Line& line; 

    template<class charT> 
    void do_input(basic_istream<charT>& is) const 
    { 
     // imbue the new locale 
     locale loc = is.imbue(locale(is.getloc(), new line_parser)); 
     is >> line; 
     is.imbue(loc); // imbue the original locale 
    } 

    template<class charT> 
    friend basic_istream<charT>& operator>>(basic_istream<charT>& is, 
              const line_extractor& le) 
    { 
     le.do_input(is); 
     return is; 
    } 
}; 

然後以削減代碼,從一個函數返回它:

template<class Line> 
line_extractor<Line> get_line(Line& l) 
{ 
    return line_extractor<Line>(l); 
} 

現在我們完成了。輸入可以做到簡單,如:

stringstream ss(line); 
vector<Line> v; 

for (Line line; ss >> get_line(line);) 
{ 
    v.push_back(line); 
} 

你也應該補充檢索的ab,並c值的方法。

Here is a demo.

+1

這似乎有點矯枉過正 –

+0

@Tim它可能會出現這種簡單的困境,但是當您擁有龐大而複雜的代碼庫時,您的代碼必須保持清晰和結構化。此代碼在概念上用於標準IOStreams插入器/提取器。 – 0x499602D2