2011-10-11 103 views
4

我有逗號分隔的字符串,我需要從拉動值。問題是這些字符串永遠不會是固定的大小。所以我決定遍歷各組逗號並閱讀它們之間的內容。爲了做到這一點,我做了一個函數,返回示例字符串中每個事件的位置。找到一個字符中所有出現的字符串

這是一個聰明的辦法做到這一點?這被認爲是不好的代碼?

#include <string> 
#include <iostream> 
#include <vector> 
#include <Windows.h> 

using namespace std; 

vector<int> findLocation(string sample, char findIt); 

int main() 
{ 
    string test = "19,,112456.0,a,34656"; 
    char findIt = ','; 

    vector<int> results = findLocation(test,findIt); 
    return 0; 
} 

vector<int> findLocation(string sample, char findIt) 
{ 
    vector<int> characterLocations; 
    for(int i =0; i < sample.size(); i++) 
     if(sample[i] == findIt) 
      characterLocations.push_back(sample[i]); 

    return characterLocations; 
} 
+1

對我來說這是完美的。雖然會有很多C++程序員說「爲什麼要發明輪子」和「使用這個功能,不要自己寫」。無論如何,我不關心他們,我不知道你。但是,您的代碼存在一個小問題。 'i'不應該達到'sample.length()',所以你應該在你的for循環條件中有'i Shahbaz

+0

Yup我剛剛修復了這個問題。此外,它需要.size()不是長度 – lodkkx

+0

如果你打算後來拆分字符串,你可能想看看[這個問題](http://stackoverflow.com/questions/236129/how-到系分割一個串入-C)。 –

回答

10
vector<int> findLocation(string sample, char findIt) 
{ 
    vector<int> characterLocations; 
    for(int i =0; i < sample.size(); i++) 
     if(sample[i] == findIt) 
      characterLocations.push_back(sample[i]); 

    return characterLocations; 
} 

上述代碼,這將簡單地返回包含字符本身,而不是他們的立場,這是你真正想要什麼,如果我正確地讀你的問題的INT表示的向量。

替換此行:

characterLocations.push_back(sample[i]); 

這一行:

characterLocations.push_back(i); 

這應該給你你想要的向量。

+0

哦,是的。接得好!我忘了那個。 – lodkkx

+4

請將頂部行更改爲向量 findLocation(const string&sample,char findIt)。我們不想複製字符串 – Totonga

6

如果我正在審查這一點,我會認爲這並假定你真正想做的是標記化的字符串,而且也已經很好的方法來做到這一點。要做到這一點我見過

最好的辦法是用boost::tokenizer。它可以讓你指定字符串是如何分隔的,然後給你一個很好的迭代器接口來迭代每個值。

using namespace boost; 
string sample = "Hello,My,Name,Is,Doug"; 
escaped_list_seperator<char> sep("" /*escape char*/, ","/*seperator*/, "" /*quotes*/) 

tokenizer<escaped_list_seperator<char> > myTokens(sample, sep) 

//iterate through the contents 
for (tokenizer<escaped_list_seperator<char>>::iterator iter = myTokens.begin(); 
    iter != myTokens.end(); 
    ++iter) 
{ 
    std::cout << *iter << std::endl; 
} 

輸出:

Hello 
My 
Name 
Is 
Doug 

編輯如果你不希望在提升依賴你,你也可以使用getlineistringstreamthis answer。從這個問題的答案多少有些拷貝:

std::string str = "Hello,My,Name,Is,Doug"; 
std::istringstream stream(str); 
std::string tok1; 

while (stream) 
{ 
    std::getline(stream, tok1, ','); 
    std::cout << tok1 << std::endl; 
} 

輸出:

Hello 
My 
Name 
Is 
Doug 

這可能不是直接你問什麼,但我認爲它會在你的整體問題,你正在試圖解決。

+0

因此,如果大小限制並不重要,那麼使用boost和其他第三方庫會更好嗎? – lodkkx

+0

'myTkoens'應該是'myTokens'。 '>>'應該是'>>'(除非OP使用C++ 11)。我無法測試這段代碼,但是你知道如何處理兩個或多個連續的分隔符? – darioo

+0

基本上我需要12個項目csv字符串中的兩個值。使用我的函數並僅將字符串分配給函數返回的索引的子字符串會不會更容易? – lodkkx

0

我看不錯過,一個評論是你的變量和類型的命名。你叫矢量你要返回characterLocations這是int類型的時候,確實你是推回字符本身(這是類型char)沒有它的位置。我不確定更大的應用程序是什麼,但我認爲將位置傳遞回去會更有意義。或者做一個更多的cookie切割器字符串標記。

0

好吧,如果你的目的是找到出現的指數下面的代碼會在C更有效++給對象作爲參數使得這些對象被複制這是不安全的,效率比較低。特別是返回一個向量是這種情況下最糟糕的做法,所以將它作爲參數引用會更好。

#include <string> 
#include <iostream> 
#include <vector> 
#include <Windows.h> 

using namespace std; 

vector<int> findLocation(string sample, char findIt); 

int main() 
{ 

    string test = "19,,112456.0,a,34656"; 
    char findIt = ','; 

    vector<int> results; 
    findLocation(test,findIt, results); 
    return 0; 
} 

void findLocation(const string& sample, const char findIt, vector<int>& resultList) 
{ 
    const int sz = sample.size(); 

    for(int i =0; i < sz; i++) 
    { 
     if(sample[i] == findIt) 
     { 
      resultList.push_back(i); 
     } 
    } 
} 
+0

爲什麼返回矢量不好? – lodkkx

+0

@chronoz:實際上,在這種情況下,返回矢量並不是那麼糟糕,因爲返回值優化會優化(可能是昂貴的)副本。但是,STL方式會將結果寫入輸出迭代器,該迭代器的類型是模板參數。因此,該功能的用戶可以選擇他想要結果的表示。 –

+0

親愛的chronoz, 在C++局部變量是從堆棧空間啓動的。當一個函數結束時,它的棧空間將被銷燬(在這種情況下,characterLocations),因此C++返回返回值的一個副本,所以變量將保持有效。在這種情況下,編譯器可能(或者可能不依賴於編譯選項)複製所有明顯減慢解決方案速度的向量。 親愛的比約恩波利克斯你是對的(特別是stl的方式真的是一個很好的解決方法),但在我看來,最好不要依賴編譯器行爲,而是要依靠自己的代碼。 – hevi

0

它有多聰明還取決於你用那些用逗號分隔的子串做什麼。在某些情況下,它可能會更好(例如,速度更快,內存要求更小),以避免搜索和分割,並且可能會使用狀態機同時解析和處理字符串。

相關問題