2012-06-09 68 views
1

我的string :: find實現有點問題。string :: find問題(C++)

輸入是一個長字符串,它由以下可能的示例組成:input =「one_thousand_and_fifty_one」。

我的問題似乎是,在一個包含多個'和'的輸入字符串中,只有第一個被刪除,其他不是。

這是我到目前爲止的代碼,它找到「和」,但只是刪除是當'a'之前的字母不是's'(表示「千」)。

string toKill = "and"; 

size_t andF = input.find(toKill); 
    if (andF != string::npos) { 
     if (input[(andF - 1)] != 's') { 
      input.erase(andF, 4); 
     } 
    } 

編輯:我忘了提,即在包含輸入唯一的其他字「和」是「千」,所以這是一個特例。

+0

那麼應你丈夫呢,還是樂隊,還是盛大的,還是android?也許你可能想檢查一個非alpha的,而不是隻是's'?也許你可能想檢查一下這個詞。 – paxdiablo

+4

對於「android」,它會崩潰,因爲它將訪問字符串範圍之外:'input [-1]'。 –

+0

@邁克爾,我知道它會做什麼,其實我更想問什麼海報_wanted_做:-) – paxdiablo

回答

3

試試這個:

string toKill = "and"; 
size_t andF = 0; 

while ((andF = input.find(toKill, andF)) != string::npos) { 
    if (andF == 0 || input[andF - 1] != 's') { 
     input.erase(andF, 4); 
    } 
    else ++andF; 
} 
+0

這工作簡單而出色。謝謝。 – Edge

+0

我想刪除4的硬編碼,只是爲了使它更通用。 –

+0

看起來我忘了需要一段時間循環。 – Edge

2

我會使用一個正則表達式這個(從升壓,PCRE或C++ 11標準) - 但如果我不得不這樣做我自己,我的代碼看起來有點像這樣:

string toKill = "and"; 
size_t pos = 0; 
while((pos = s.find(toKill, pos))!=std::string::n_pos) 
{ 
    //Check it doesn't start with an additional letter 
    if(pos!=0 && is_alpha(s[pos-1])) { pos++; continue; } 
    //Check it doesn't end with an additional letter 
    if(pos+toKill.size()!=s.size() && is_alpha(s[pos+toKill.size()]) { pos++; continue;} 
    //Remove it and the trailing whitespace (or punctuation) 
    s.erase(pos,toKill.size()+1); 
} 
+0

無限循環如果字符串包含千位。 – fbafelipe

+0

如果你不調用'erase()',你將需要從'pos'搜索,否則你會得到一個無限循環 – Attila

+0

是的。現在修復。 –

2

您的代碼中至少需要其他兩件事。第一個是處理整個字符串的循環,用於處理and字符串,第二個是可以跳過已經檢查過的字符串。

您可能還需要來處理該字符串可以開始and的可能性,儘管是不可能的:是自由的與你的期望和具體跟你提供什麼。

下面的代碼將是一個很好的起點:

#include <iostream> 
#include <string> 

int main (void) { 
    std::string inputStr = "one thousand and fifty one"; 
    std::string killStr = "and "; 

    size_t startPos = 0; 
    size_t andPos; 
    while ((andPos = inputStr.find (killStr, startPos)) != std::string::npos) { 
     if ((andPos == 0) || (inputStr[(andPos - 1)] != 's')) { 
      inputStr.erase(andPos, killStr.length()); 
      startPos = andPos; 
     } else { 
      startPos = andPos + 1; 
     } 
    } 

    std::cout << inputStr << '\n'; 
    return 0; 
} 

而且,因爲我是偏執在字符串的開頭有and,邁克爾理所當然地叫我上在不處理它結束串的(一),你可以修改它做的東西像這樣做:

#include <iostream> 
#include <string> 
#include <cstring> 

static bool endsWith (std::string s1, std::string s2) { 
    size_t s1Len = s1.length(); 
    size_t s2Len = s2.length(); 
    if (s2Len > s1Len) 
     return false; 
    return (strcmp (s1.c_str() + s1Len - s2Len, s2.c_str()) == 0); 
} 

int main (void) { 
    std::string inputStr = "and one thousand and fifty one thousand and"; 
    std::string killStr = "and "; 

    size_t startPos = 0; 
    size_t andPos; 
    while ((andPos = inputStr.find (killStr, startPos)) != std::string::npos) { 
     if ((andPos == 0) || (inputStr[(andPos - 1)] != 's')) { 
      inputStr.erase (andPos, killStr.length()); 
      startPos = andPos; 
     } else { 
      startPos = andPos + 1; 
     } 
    } 
    if (!endsWith (inputStr, "sand") && endsWith (inputStr, "and")) 
     inputStr.erase (inputStr.length() - 3); 

    std::cout << inputStr << '\n'; 
    return 0; 
} 

(一)如果我要成爲一個學究,我最好也做正確:-)

+0

我喜歡給toKill字符串添加空格 - 它修復了尾隨字符問題。然而,它不會趕上一個尾隨的「和」 - 就像「一百」,但我假設對於OP案件可以。 –