2014-12-08 85 views
1

我被困在設計這個功能:解析兩個或一個號::串

//Turns "[0-9]+,[0-9]+" into two integers. Turns "[0-9]+" in two *equal* integers 
static void parseRange(const std::string, int&, int&); 

我沒有獲得正則表達式(這需要無論是C++ 11或Boost庫)。我需要以某種方式查明該字符串是否包含2個整數並將其分開,然後獲取每個整數。

我想我需要strstr版本使用std::string找出是否有逗號和地方。我可能可以用std::string::c_str值運作。廣泛的搜索使我這個(但我想用std::string,不C字符串):

void Generator::parseRange(const std::string str, int& min, int& max) { 
     const char* cstr = str.c_str(); 
     const char* comma_pos; 
     //There's a comma 
     if((comma_pos=strstr(cstr, ","))!=NULL) { //(http://en.cppreference.com/w/cpp/string/byte/strstr) 
      //The distance between begining of string and the comma??? 
      //Can I do this thing with pointers??? 
      //Is 1 unit of pointer really 1 character??? 
      unsigned int num_len = (comma_pos-cstr); 
      //Create new C string and copy the first part to it (http://stackoverflow.com/q/8164000/607407) 
      char* first_number=(char *)malloc((num_len+1)*sizeof(char));//+1 for \0 character 
      //Make sure it ends with \0 
      first_number[num_len] = 0; 
      //Copy the other string to it 
      memcpy(first_number, cstr, num_len*sizeof(char)); 
      //Use atoi 
      min = atoi(first_number); 
      max = atoi(comma_pos+1); 
      //free memory - thanks @Christophe 
      free(first_number); 
     } 
     //Else just convert string to int. Easy as long as there's no messed up input 
     else { 
      min = atoi(cstr); //(http://www.cplusplus.com/reference/cstdlib/atoi/) 
      max = atoi(cstr); 
     } 
    } 

我Google了很多。你不能說我沒有嘗試。上面的函數有效,但我更喜歡一些不那麼天真的實現,因爲你上面看到的是來自舊時代的硬核C代碼。這一切都依賴於沒有人因輸入而混淆的事實。

+0

1)在C++中避免malloc()! 2)你內存泄漏 – Christophe 2014-12-08 01:03:19

+0

這就是爲什麼我要求C++解決方案。在學校裏,他們只教我們C,我正在盡我所能,這顯然是我想要的。 – 2014-12-08 01:04:45

回答

2

您可以通過使用內置的不復印或使用mallocnew存儲部分字符串需要與std::atoi沿std::string提供搜索功能做到這一點。

#include <cstdlib> 
#include <string> 

void Generator::parseRange(const std::string &str, int& min, int& max) 
{ 
    // Get the first integer 
    min = std::atoi(&str[0]); 

    // Check if there's a command and proces the second integer if there is one 
    std::string::size_type comma_pos = str.find(','); 
    if (comma_pos != std::string::npos) 
    { 
     max = std::atoi(&str[comma_pos + 1]); 
    } 
    // No comma, min and max are the same 
    else 
    { 
     max = min; 
    } 
} 

另外,正如其他人指出的那樣,您可以使用std::istringstream來處理整數解析。這將允許你做額外的輸入驗證時解析整數值

#include <sstream> 
#include <string> 

bool Generator::parseRange(const std::string& str, int& min, int& max) 
{ 
    std::istringstream sst(str); 

    // Read in the first integer 
    if (!(sst >> min)) 
    { 
     return false; 
    } 

    // Check for comma. Could also check and error out if additional invalid input is 
    // in the stream 
    if (sst.get() != ',') 
    { 
     max = min; 
     return true; 
    } 

    // Read in the second integer 
    if (!(sst >> max)) 
    { 
     return false; 
    } 

    return true; 
} 
+0

「istringstream」解決方案是最完美的。我只會添加臨時變量,如果無效'「666,」通過(因爲不清楚打算輸入什麼內容),將臨時變量恢復爲原來的狀態。否則完美,謝謝。 – 2014-12-08 01:36:18

1

什麼這個更原生版本:

void Generator::parseRange(const std::string str, int& min, int& max) { 
    stringstream sst(str); 
    if (!(sst>>min && sst.get()==',' && sst>>max)) 
     cerr<<"String has an invalid format\n"; 
    } 
+0

如果它失敗了,它會把任何東西放在整數中嗎?我其實有一些默認值,所以最好如果失敗並且不改變它的值。 – 2014-12-08 01:12:26

+0

它不會覆蓋失敗的整數。但是,如果第一個整數有效,它將被存儲,即使第二個整數無效。 – Christophe 2014-12-08 09:08:42

1

你可以做所有的搜索和與std::string功能很容易分離。

int pos = str.find(','); 

assert(pos != std::string::npos); 

std::string first = str.substr(0, pos); 
std::string second = str.substr(pos+1, -1); 

另外,你可以很容易地做一個stringstream解析。例如:

std::istringstream s(str); 

int one, two; 
char ch; 

s >> one >> ch >> two; 

assert(ch == ','); 

請注意,這也可以很容易地將分隔字符串和將單個字符轉換爲數字。

1

無需的std ::什麼,它只會消耗更多的內存爲一個也不能少不可讀的代碼。

試試這個大約1980年的C代碼,它應該做的伎倆:

void generator::parse_range (const std::string input, int & min, int & max) 
{ 
    const char * scan = input.c_str(); 
    min = (int) strtol (scan, &scan, 0); 
    max = (*scan == ',') ? (int)strtol (scan+1, &scan, 0) : min; 
    if (errno || *scan != '\0') panic ("you call that numbers?"); 
} 

這將接受十六進制或八進制的投入,但你可以修復與第三個參數的基礎。
你也可以在第一次轉換或測試長整數溢出後檢查errno,但我認爲這不是你問題中最糟糕的部分:)

+1

我想這是最快的解決方案。感謝您展示C還沒有死:) – 2014-12-08 01:37:25

+1

如果沒有有效的格式被識別,errno將被設置爲EINVAL並且strtol將返回0.您必須執行檢查以保留您的默認值。至於C還活着還是死了,好吧,歸咎於Stourstrup先生和他的朋友們在過去的25年左右無法提供體面的絃樂處理套裝...... – 2014-12-08 01:43:32