Ich analysiere eine Zeichenfolge in C++ mit folgendem Befehl:
string parsed,input="text to be parsed";
stringstream input_stringstream(input);
if(getline(input_stringstream,parsed,' '))
{
// do some processing.
}
Das Parsen mit einem einzelnen Zeichen als Trennzeichen ist in Ordnung. Was aber, wenn ich einen String als Trennzeichen verwenden möchte.
Beispiel: Ich möchte teilen:
scott>=tiger
mit> = als Trennzeichen, damit ich Scott und Tiger bekommen kann.
Sie können die Funktion std::string::find()
verwenden, um die Position Ihres Zeichenfolge-Trennzeichens zu ermitteln, und dann mit std::string::substr()
ein Token abrufen.
Beispiel:
std::string s = "scott>=tiger";
std::string delimiter = ">=";
std::string token = s.substr(0, s.find(delimiter)); // token is "scott"
Die Funktion find(const string& str, size_t pos = 0)
gibt die Position des ersten Vorkommens von str
in der Zeichenfolge zurück bzw. npos
, falls die Zeichenfolge nicht gefunden wird.
Die Funktion substr(size_t pos = 0, size_t n = npos)
gibt einen Teilstring des Objekts zurück, beginnend an Position pos
und der Länge npos
.
Wenn Sie mehrere Trennzeichen haben, nachdem Sie ein Token extrahiert haben, können Sie es entfernen (Trennzeichen enthalten), um mit nachfolgenden Extraktionen fortzufahren (wenn Sie den ursprünglichen String beibehalten möchten, verwenden Sie einfach s = s.substr(pos + delimiter.length());
):
s.erase(0, s.find(delimiter) + delimiter.length());
Auf diese Weise können Sie leicht einen Loop erstellen, um jedes Token zu erhalten.
std::string s = "scott>=tiger>=mushroom";
std::string delimiter = ">=";
size_t pos = 0;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) {
token = s.substr(0, pos);
std::cout << token << std::endl;
s.erase(0, pos + delimiter.length());
}
std::cout << s << std::endl;
Ausgabe:
scott
tiger
mushroom
Diese Methode verwendet std::string::find
, ohne die ursprüngliche Zeichenfolge zu mutieren, indem der Anfang und das Ende des vorherigen Teilzeichenfolgetokens gespeichert werden.
#include <iostream>
#include <string>
int main()
{
std::string s = "scott>=tiger";
std::string delim = ">=";
auto start = 0U;
auto end = s.find(delim);
while (end != std::string::npos)
{
std::cout << s.substr(start, end - start) << std::endl;
start = end + delim.length();
end = s.find(delim, start);
}
std::cout << s.substr(start, end);
}
Mit der nächsten Funktion können Sie die Zeichenfolge teilen:
vector<string> split(const string& str, const string& delim)
{
vector<string> tokens;
size_t prev = 0, pos = 0;
do
{
pos = str.find(delim, prev);
if (pos == string::npos) pos = str.length();
string token = str.substr(prev, pos-prev);
if (!token.empty()) tokens.Push_back(token);
prev = pos + delim.length();
}
while (pos < str.length() && prev < str.length());
return tokens;
}
Mit strtok können Sie mehrere Zeichen als Trennzeichen übergeben. Ich wette, wenn Sie "> =" übergeben, wird Ihr Beispielstring korrekt aufgeteilt (obwohl> und = als einzelne Trennzeichen gezählt werden).
EDIT Wenn Sie c_str()
nicht zur Konvertierung von Zeichenfolge in Zeichen * verwenden möchten, können Sie substr und find_first_of zum tokenize verwenden.
string token, mystring("scott>=tiger");
while(token != mystring){
token = mystring.substr(0,mystring.find_first_of(">="));
mystring = mystring.substr(mystring.find_first_of(">=") + 1);
printf("%s ",token.c_str());
}
Zeichenfolge basierend auf einem Zeichenfolge-Trennzeichen aufteilen. B. die Zeichenfolge "adsf-+qwret-+nvfkbdsj-+orthdfjgh-+dfjrleih"
basierend auf dem Zeichenfolgenbegrenzer "-+"
, wird die Ausgabe {"adsf", "qwret", "nvfkbdsj", "orthdfjgh", "dfjrleih"}
.__ ausgegeben.
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
// for string delimiter
vector<string> split (string s, string delimiter) {
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
string token;
vector<string> res;
while ((pos_end = s.find (delimiter, pos_start)) != string::npos) {
token = s.substr (pos_start, pos_end - pos_start);
pos_start = pos_end + delim_len;
res.Push_back (token);
}
res.Push_back (s.substr (pos_start));
return res;
}
int main() {
string str = "adsf-+qwret-+nvfkbdsj-+orthdfjgh-+dfjrleih";
string delimiter = "-+";
vector<string> v = split (str, delimiter);
for (auto i : v) cout << i << endl;
return 0;
}
Ausgabe
adsf qwret nvfkbdsj orthdfjgh dfjrleih
Zeichenfolge basierend auf einem Zeichenbegrenzer aufgeteilt. B. die Zeichenfolge "adsf+qwer+poui+fdgh"
mit dem Trennzeichen "+"
, wird {"adsf", "qwer", "poui", "fdg"h}
.__ ausgegeben.
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
vector<string> split (const string &s, char delim) {
vector<string> result;
stringstream ss (s);
string item;
while (getline (ss, item, delim)) {
result.Push_back (item);
}
return result;
}
int main() {
string str = "adsf+qwer+poui+fdgh";
vector<string> v = split (str, '+');
for (auto i : v) cout << i << endl;
return 0;
}
Ausgabe
adsf qwer poui fdgh
Dieser Code trennt Zeilen von Text und fügt alle zu einem Vektor hinzu.
vector<string> split(char *phrase, string delimiter){
vector<string> list;
string s = string(phrase);
size_t pos = 0;
string token;
while ((pos = s.find(delimiter)) != string::npos) {
token = s.substr(0, pos);
list.Push_back(token);
s.erase(0, pos + delimiter.length());
}
list.Push_back(s);
return list;
}
Angerufen von:
vector<string> listFilesMax = split(buffer, "\n");
Ich würde boost::tokenizer
verwenden. Hier ist eine Dokumentation, die erläutert, wie Sie eine geeignete Tokenizer-Funktion erstellen: http://www.boost.org/doc/libs/1_52_0/libs/tokenizer/tokenizerfunction.htm
Hier ist eines, das für Ihren Fall funktioniert.
struct my_tokenizer_func
{
template<typename It>
bool operator()(It& next, It end, std::string & tok)
{
if (next == end)
return false;
char const * del = ">=";
auto pos = std::search(next, end, del, del + 2);
tok.assign(next, pos);
next = pos;
if (next != end)
std::advance(next, 2);
return true;
}
void reset() {}
};
int main()
{
std::string to_be_parsed = "1) one>=2) two>=3) three>=4) four";
for (auto i : boost::tokenizer<my_tokenizer_func>(to_be_parsed))
std::cout << i << '\n';
}
Hier ist meine Meinung dazu. Es behandelt die Edge-Fälle und benötigt einen optionalen Parameter, um leere Einträge aus den Ergebnissen zu entfernen.
bool endsWith(const std::string& s, const std::string& suffix)
{
return s.size() >= suffix.size() &&
s.substr(s.size() - suffix.size()) == suffix;
}
std::vector<std::string> split(const std::string& s, const std::string& delimiter, const bool& removeEmptyEntries = false)
{
std::vector<std::string> tokens;
for (size_t start = 0, end; start < s.length(); start = end + delimiter.length())
{
size_t position = s.find(delimiter, start);
end = position != string::npos ? position : s.length();
std::string token = s.substr(start, end - start);
if (!removeEmptyEntries || !token.empty())
{
tokens.Push_back(token);
}
}
if (!removeEmptyEntries &&
(s.empty() || endsWith(s, delimiter)))
{
tokens.Push_back("");
}
return tokens;
}
Beispiele
split("a-b-c", "-"); // [3]("a","b","c")
split("a--c", "-"); // [3]("a","","c")
split("-b-", "-"); // [3]("","b","")
split("--c--", "-"); // [5]("","","c","","")
split("--c--", "-", true); // [1]("c")
split("a", "-"); // [1]("a")
split("", "-"); // [1]("")
split("", "-", true); // [0]()
Dies ist eine vollständige Methode, die die Zeichenfolge auf ein beliebiges Trennzeichen aufteilt und einen Vektor der zerlegten Zeichenfolgen zurückgibt.
Es ist eine Adaption aus der Antwort von RyanBwork. Seine Prüfung auf: if(token != mystring)
führt jedoch zu falschen Ergebnissen, wenn Ihre Zeichenfolge sich wiederholende Elemente enthält. Dies ist meine Lösung für dieses Problem.
vector<string> Split(string mystring, string delimiter)
{
vector<string> subStringList;
string token;
while (true)
{
size_t findfirst = mystring.find_first_of(delimiter);
if (findfirst == string::npos) //find_first_of returns npos if it couldn't find the delimiter anymore
{
subStringList.Push_back(mystring); //Push back the final piece of mystring
return subStringList;
}
token = mystring.substr(0, mystring.find_first_of(delimiter));
mystring = mystring.substr(mystring.find_first_of(delimiter) + 1);
subStringList.Push_back(token);
}
return subStringList;
}
Wenn Sie die Zeichenfolge nicht ändern möchten (wie in der Antwort von Vincenzo Pii) und auch das letzte Token ausgeben möchten, können Sie diesen Ansatz verwenden:
inline std::vector<std::string> splitString( const std::string &s, const std::string &delimiter ){
std::vector<std::string> ret;
size_t start = 0;
size_t end = 0;
size_t len = 0;
std::string token;
do{ end = s.find(delimiter,start);
len = end - start;
token = s.substr(start, len);
ret.emplace_back( token );
start += len + delimiter.length();
std::cout << token << std::endl;
}while ( end != std::string::npos );
return ret;
}
#include<iostream>
#include<algorithm>
using namespace std;
int split_count(string str,char delimit){
return count(str.begin(),str.end(),delimit);
}
void split(string str,char delimit,string res[]){
int a=0,i=0;
while(a<str.size()){
res[i]=str.substr(a,str.find(delimit));
a+=res[i].size()+1;
i++;
}
}
int main(){
string a="abc.xyz.mno.def";
int x=split_count(a,'.')+1;
string res[x];
split(a,'.',res);
for(int i=0;i<x;i++)
cout<<res[i]<<endl;
return 0;
}
PS: Funktioniert nur, wenn die Länge der Zeichenfolgen nach dem Teilen gleich ist
Die Antwort ist bereits vorhanden, bei der ausgewählten Antwort wird jedoch die Löschfunktion verwendet, die sehr kostspielig ist. Denken Sie an eine sehr große Zeichenfolge (in MB). Deshalb benutze ich untenstehende Funktion.
vector<string> split(const string& i_str, const string& i_delim)
{
vector<string> result;
size_t found = i_str.find(i_delim);
size_t startIndex = 0;
while(found != string::npos)
{
string temp(i_str.begin()+startIndex, i_str.begin()+found);
result.Push_back(temp);
startIndex = found + i_delim.size();
found = i_str.find(i_delim, startIndex);
}
if(startIndex != i_str.size())
result.Push_back(string(i_str.begin()+startIndex, i_str.end()));
return result;
}