[英]Splitting a string on two delimitators in C++
我有一個文件,citys.txt,其中包含:
Hayward - San Lorenzo
San Lorenzo - Oakland
Dublin - San Jose
San Mateo - Hayward
San Francisco - Daly City
San Mateo - Oakland
San Francisco - Oakland
Freemont - Hayward
San Lorenzo - Dublin
San Jose - San Mateo
Daly City - San Raphael
我通過以下方式閱讀了文件競賽:
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
int main( ) {
std::ifstream infile( "cities.txt" ) ;
if ( infile ) {
std::string fileData( ( std::istreambuf_iterator<char> ( infile ) ) ,
std::istreambuf_iterator<char> ( ) ) ;
infile.close( );
std::cout << fileData <<"\n\n";
return 0 ;
}
else {
std::cout << "Where is cities.txt?\n" ;
return 1 ;
}
}
並將內容保存在fileData字符串中。 我需要將該字符串分成僅包含城市名稱的字符串列表。 像這樣:
list = {"Hayward","San Lorenzo", "San Lorenzo", "Oakland"......}
我打算將字符串轉換為char *並使用strtok,但是似乎可以使用標准字符串函數完成很多工作。 有沒有辦法既快速又簡潔?
我可能會使用std::getline
,將-
指定為元素之間的分隔符:
std::string city;
while (std::getline(i, city, '-'))
cities.push_back(city);
一個小細節:這將保留空白,因此,如果前導和/或尾隨空白是一個問題,則必須單獨進行修剪。
您可以分兩步執行此操作。
將文件的內容分割為字符串向量-因此,向量的每個元素將包含文件的單行
將文件的每一行拆分為兩個元素(該行中的兩個城市)
修剪內容
split函數可以這樣實現:
vector<string> split (string str, string seq) {
vector<string> ret {};
size_t pos {};
while ((pos = str.find (seq)) != string::npos) {
ret.push_back (str.substr (0, pos));
str = str.substr (pos+seq.size ());
}
ret.push_back (str);
return ret;
}
整理功能可以這樣實現:
string ltrim (string s) {
s.erase (s.begin (), find_if (s.begin (), s.end (), not1 (ptr_fun<int, int> (isspace))));
return s;
}
string rtrim (string s) {
s.erase (find_if (s.rbegin (), s.rend (), not1 (ptr_fun<int, int> (isspace))).base (), s.end ());
return s;
}
string trim (string s) {
return ltrim (rtrim (s));
}
因此,基本上,您有了所有需要的東西,讓我們准備一個結果函數。
vector<string> result (vector<string>&& content) {
vector<string> ret {};
for (const auto& c : content) {
auto vec = split (c, "-"); // (2)
for (const auto& v : vec) {
ret.push_back (trim (v));
}
}
return ret;
}
void show (const vector<string>& vec) {
for (const auto& v : vec) {
cout << "|" << v << "|" << endl;
}
}
並假設文件內容位於content對象中,使用情況如下所示。
auto vec = result (split (content, "\n")); // (1)
show (vec);
現在,需要一些解釋。 讓我們來看看(1)我們把文件的全部內容(我錯過了檢索從文件的內容),並創建一個字符串矢量,在這種情況下,它是一個行向量(從文件,因為以次 uence是“\\ n”)。 因此,我們將傳遞文件中行的結果函數向量。 好吧,簡單,讓我們繼續。 現在我們就來此行分成兩個字符串(市)(2),但我們的SEQ uence現在是“ - ”。 此(2)調用將產生字符串向量,其中將包含城市名稱。 現在,我們要做的就是將這些名稱添加到將返回的矢量ret中,但是首先修剪內容以使左側和右側的所有空白都消失。
結果是:
|Hayward|
|San Lorenzo|
|San Lorenzo|
|Oakland|
|Dublin|
|San Jose|
|San Mateo|
|Hayward|
|San Francisco|
|Daly City|
|San Mateo|
|Oakland|
|San Francisco|
|Oakland|
|Freemont|
|Hayward|
|San Lorenzo|
|Dublin|
|San Jose|
|San Mateo|
|Daly City|
|San Raphael|
您可以使用string :: find,string :: erase和string :: substr
使用while循環,類似於found = input.find("-"); while(found != string::npos){... }
found = input.find("-"); while(found != string::npos){... }
在while子字符串中輸入城市名稱,然后使用.erase(position,length)從整個字符串中刪除城市
您可以使用boost regex_split。 我已經修改了您的代碼以演示相同的內容。 粘貼在下面:
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <boost/regex.hpp>
#include <vector>
int main( ) {
std::ifstream infile( "cities.txt" ) ;
if ( infile ) {
std::string fileData( ( std::istreambuf_iterator<char> ( infile ) ) ,
std::istreambuf_iterator<char> ( ) ) ;
infile.close( );
std::cout << fileData <<"\n\n";
std::vector<std::string> out;
// Delimeter regular expression
boost::regex delims("\\s+-\\s+|\n|\r");
boost::regex_split(std::back_inserter(out), fileData, delims);
for (auto &city : out) {
std::cout << city << std::endl;
}
}
else {
std::cout << "Where is cities.txt?\n" ;
return 1 ;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.