Nazywa się to przycinaniem. Jeśli możesz użyć Boost , polecam to.
W przeciwnym razie użyj, find_first_not_of
aby pobrać indeks pierwszego niebiałego znaku, a następnie find_last_not_of
pobrać indeks od końca, który nie jest białą spacją. Z nimi użyj, substr
aby uzyskać podciąg bez otaczających białych znaków.
W odpowiedzi na twoją edycję nie znam terminu, ale zgaduję, że jest to coś w rodzaju „zmniejsz”, więc tak to nazwałem. :) (Uwaga, odstępy zostały zmienione na parametr, aby zwiększyć elastyczność)
#include <iostream>
#include <string>
std::string trim(const std::string& str,
const std::string& whitespace = " \t")
{
const auto strBegin = str.find_first_not_of(whitespace);
if (strBegin == std::string::npos)
return "";
const auto strEnd = str.find_last_not_of(whitespace);
const auto strRange = strEnd - strBegin + 1;
return str.substr(strBegin, strRange);
}
std::string reduce(const std::string& str,
const std::string& fill = " ",
const std::string& whitespace = " \t")
{
auto result = trim(str, whitespace);
auto beginSpace = result.find_first_of(whitespace);
while (beginSpace != std::string::npos)
{
const auto endSpace = result.find_first_not_of(whitespace, beginSpace);
const auto range = endSpace - beginSpace;
result.replace(beginSpace, range, fill);
const auto newStart = beginSpace + fill.length();
beginSpace = result.find_first_of(whitespace, newStart);
}
return result;
}
int main(void)
{
const std::string foo = " too much\t \tspace\t\t\t ";
const std::string bar = "one\ntwo";
std::cout << "[" << trim(foo) << "]" << std::endl;
std::cout << "[" << reduce(foo) << "]" << std::endl;
std::cout << "[" << reduce(foo, "-") << "]" << std::endl;
std::cout << "[" << trim(bar) << "]" << std::endl;
}
Wynik:
[too much space]
[too much space]
[too-much-space]
[one
two]
site_t
byćsize_t
? I myślę, że miejsce, w którym masz komentarz,no whitespace
oznacza, że cały ciąg jest spacji lub pusty.size_t
poprawiłem literówkę i pojedynczo w edycji, ale nie zauważyłem, że mój komentarz został odwrócony, dzięki.Łatwe usuwanie początkowych, końcowych i dodatkowych spacji ze std :: string w jednej linii
value = std::regex_replace(value, std::regex("^ +| +$|( ) +"), "$1");
usuwanie tylko wiodących spacji
value.erase(value.begin(), std::find_if(value.begin(), value.end(), std::bind1st(std::not_equal_to<char>(), ' ')));
lub
value = std::regex_replace(value, std::regex("^ +"), "");
usuwanie tylko spacji końcowych
value.erase(std::find_if(value.rbegin(), value.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), value.end());
lub
value = std::regex_replace(value, std::regex(" +$"), "");
usuwanie tylko dodatkowych spacji
value = regex_replace(value, std::regex(" +"), " ");
źródło
substr
luberase
).Obecnie używam tych funkcji:
// trim from left inline std::string& ltrim(std::string& s, const char* t = " \t\n\r\f\v") { s.erase(0, s.find_first_not_of(t)); return s; } // trim from right inline std::string& rtrim(std::string& s, const char* t = " \t\n\r\f\v") { s.erase(s.find_last_not_of(t) + 1); return s; } // trim from left & right inline std::string& trim(std::string& s, const char* t = " \t\n\r\f\v") { return ltrim(rtrim(s, t), t); } // copying versions inline std::string ltrim_copy(std::string s, const char* t = " \t\n\r\f\v") { return ltrim(s, t); } inline std::string rtrim_copy(std::string s, const char* t = " \t\n\r\f\v") { return rtrim(s, t); } inline std::string trim_copy(std::string s, const char* t = " \t\n\r\f\v") { return trim(s, t); }
źródło
Zwiększ algorytm przycinania ciągów
#include <boost/algorithm/string/trim.hpp> [...] std::string msg = " some text with spaces "; boost::algorithm::trim(msg);
źródło
To jest moje rozwiązanie do usuwania spacji wiodącej i końcowej ...
std::string stripString = " Plamen "; while(!stripString.empty() && std::isspace(*stripString.begin())) stripString.erase(stripString.begin()); while(!stripString.empty() && std::isspace(*stripString.rbegin())) stripString.erase(stripString.length()-1);
Wynik to „Plamen”
źródło
Oto jak możesz to zrobić:
std::string & trim(std::string & str) { return ltrim(rtrim(str)); }
Funkcje pomocnicze są realizowane jako:
std::string & ltrim(std::string & str) { auto it2 = std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } ); str.erase( str.begin() , it2); return str; } std::string & rtrim(std::string & str) { auto it1 = std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } ); str.erase( it1.base() , str.end() ); return str; }
A kiedy już to wszystko na miejscu, możesz również napisać to:
std::string trim_copy(std::string const & str) { auto s = str; return ltrim(rtrim(s)); }
Spróbuj tego
źródło
Przykład przycinania wiodących i końcowych spacji zgodnie z sugestią Jon-Hansona, aby użyć wzmocnienia (usuwa tylko końcowe i oczekujące spacje):
#include <boost/algorithm/string/trim.hpp> std::string str = " t e s t "; boost::algorithm::trim ( str );
Prowadzi do
"t e s t"
Jest również
trim_left
prowadzi do"t e s t "
trim_right
prowadzi do" t e s t"
źródło
/// strip a string, remove leading and trailing spaces void strip(const string& in, string& out) { string::const_iterator b = in.begin(), e = in.end(); // skipping leading spaces while (isSpace(*b)){ ++b; } if (b != e){ // skipping trailing spaces while (isSpace(*(e-1))){ --e; } } out.assign(b, e); }
W powyższym kodzie funkcja isSpace () jest funkcją logiczną, która mówi, czy znak jest odstępem, możesz zaimplementować tę funkcję, aby odzwierciedlić swoje potrzeby, lub po prostu wywołać funkcję isspace () z „ctype.h”, jeśli chcesz .
źródło
Przykład przycinania spacji wiodących i końcowych
std::string aString(" This is a string to be trimmed "); auto start = aString.find_first_not_of(' '); auto end = aString.find_last_not_of(' '); std::string trimmedString; trimmedString = aString.substr(start, (end - start) + 1);
LUB
trimmedSring = aString.substr(aString.find_first_not_of(' '), (aString.find_last_not_of(' ') - aString.find_first_not_of(' ')) + 1);
źródło
Korzystanie z biblioteki standardowej ma wiele zalet, ale należy pamiętać o pewnych specjalnych przypadkach, które powodują wyjątki. Na przykład żadna z odpowiedzi nie dotyczyła przypadku, w którym ciąg w C ++ ma kilka znaków Unicode. W takim przypadku, jeśli użyjesz funkcji isspace , zostanie zgłoszony wyjątek.
Używałem następującego kodu do przycinania ciągów i innych operacji, które mogą się przydać. Główne zalety tego kodu to: jest naprawdę szybki (szybszy niż jakikolwiek kod, który kiedykolwiek testowałem), używa tylko standardowej biblioteki i nigdy nie powoduje wyjątku:
#include <string> #include <algorithm> #include <functional> #include <locale> #include <iostream> typedef unsigned char BYTE; std::string strTrim(std::string s, char option = 0) { // convert all whitespace characters to a standard space std::replace_if(s.begin(), s.end(), (std::function<int(BYTE)>)::isspace, ' '); // remove leading and trailing spaces size_t f = s.find_first_not_of(' '); if (f == std::string::npos) return ""; s = s.substr(f, s.find_last_not_of(' ') - f + 1); // remove consecutive spaces s = std::string(s.begin(), std::unique(s.begin(), s.end(), [](BYTE l, BYTE r){ return l == ' ' && r == ' '; })); switch (option) { case 'l': // convert to lowercase std::transform(s.begin(), s.end(), s.begin(), ::tolower); return s; case 'U': // convert to uppercase std::transform(s.begin(), s.end(), s.begin(), ::toupper); return s; case 'n': // remove all spaces s.erase(std::remove(s.begin(), s.end(), ' '), s.end()); return s; default: // just trim return s; } }
źródło
To może być najprostsze ze wszystkich.
Możesz użyć
string::find
i,string::rfind
aby znaleźć białe znaki z obu stron i zredukować ciąg.void TrimWord(std::string& word) { if (word.empty()) return; // Trim spaces from left side while (word.find(" ") == 0) { word.erase(0, 1); } // Trim spaces from right side size_t len = word.size(); while (word.rfind(" ") == --len) { word.erase(len, len + 1); } }
źródło
Przetestowałem to, wszystko działa. Więc ta metoda processInput po prostu poprosi użytkownika o wpisanie czegoś. Zwróci łańcuch, który nie ma wewnętrznych spacji ani dodatkowych spacji na początku lub na końcu. Mam nadzieję że to pomoże. (umieść także stos komentarzy, aby ułatwić zrozumienie).
możesz zobaczyć, jak to zaimplementować w main () na dole
#include <string> #include <iostream> string processInput() { char inputChar[256]; string output = ""; int outputLength = 0; bool space = false; // user inputs a string.. well a char array cin.getline(inputChar,256); output = inputChar; string outputToLower = ""; // put characters to lower and reduce spaces for(int i = 0; i < output.length(); i++){ // if it's caps put it to lowercase output[i] = tolower(output[i]); // make sure we do not include tabs or line returns or weird symbol for null entry array thingy if (output[i] != '\t' && output[i] != '\n' && output[i] != 'Ì') { if (space) { // if the previous space was a space but this one is not, then space now is false and add char if (output[i] != ' ') { space = false; // add the char outputToLower+=output[i]; } } else { // if space is false, make it true if the char is a space if (output[i] == ' ') { space = true; } // add the char outputToLower+=output[i]; } } } // trim leading and tailing space string trimmedOutput = ""; for(int i = 0; i < outputToLower.length(); i++){ // if it's the last character and it's not a space, then add it // if it's the first character and it's not a space, then add it // if it's not the first or the last then add it if (i == outputToLower.length() - 1 && outputToLower[i] != ' ' || i == 0 && outputToLower[i] != ' ' || i > 0 && i < outputToLower.length() - 1) { trimmedOutput += outputToLower[i]; } } // return output = trimmedOutput; return output; } int main() { cout << "Username: "; string userName = processInput(); cout << "\nModified Input = " << userName << endl; }
źródło
Po co komplikować?
std::string removeSpaces(std::string x){ if(x[0] == ' ') { x.erase(0, 1); return removeSpaces(x); } if(x[x.length() - 1] == ' ') { x.erase(x.length() - 1, x.length()); return removeSpaces(x); } else return x; }
Działa to nawet jeśli boost miał się nie powieść, bez wyrażenia regularnego, bez dziwnych rzeczy ani bibliotek.
EDYCJA: Naprawiono komentarz MM.
źródło
Wprowadzono C ++ 17
std::basic_string_view
, szablon klasy, który odwołuje się do stałej, ciągłej sekwencji obiektów typu char, czyli widoku łańcucha. Oprócz bardzo podobnego interfejsu dostd::basic_string
, ma dwie dodatkowe funkcjeremove_prefix()
:, która zmniejsza widok, przesuwając jego początek do przodu; iremove_suffix()
, która zmniejsza widok, przesuwając jego koniec do tyłu. Można ich użyć do przycięcia spacji wiodącej i końcowej:#include <string_view> #include <string> std::string_view ltrim(std::string_view str) { const auto pos(str.find_first_not_of(" \t")); str.remove_prefix(pos); return str; } std::string_view rtrim(std::string_view str) { const auto pos(str.find_last_not_of(" \t")); str.remove_suffix(str.length() - pos - 1); return str; } std::string_view trim(std::string_view str) { str = ltrim(str); str = rtrim(str); return str; } int main() { std::string str = " hello world "; auto sv1{ ltrim(str) }; // "hello world " auto sv2{ rtrim(str) }; // " hello world" auto sv3{ trim(str) }; // "hello world" //If you want, you can create std::string objects from std::string_view objects auto s1{ sv1 }; auto s2{ sv2 }; auto s3{ sv3 }; }
Uwaga: nie
std::string_view
jest to odniesienie, które nie jest właścicielem, więc jest ważne tylko tak długo, jak długo istnieje oryginalny ciąg.źródło
char *str = (char*) malloc(50 * sizeof(char)); strcpy(str, " some random string (<50 chars) "); while(*str == ' ' || *str == '\t' || *str == '\n') str++; int len = strlen(str); while(len >= 0 && (str[len - 1] == ' ' || str[len - 1] == '\t' || *str == '\n') { *(str + len - 1) = '\0'; len--; } printf(":%s:\n", str);
źródło
void removeSpaces(string& str) { /* remove multiple spaces */ int k=0; for (int j=0; j<str.size(); ++j) { if ( (str[j] != ' ') || (str[j] == ' ' && str[j+1] != ' ' )) { str [k] = str [j]; ++k; } } str.resize(k); /* remove space at the end */ if (str [k-1] == ' ') str.erase(str.end()-1); /* remove space at the begin */ if (str [0] == ' ') str.erase(str.begin()); }
źródło
string trim(const string & sStr) { int nSize = sStr.size(); int nSPos = 0, nEPos = 1, i; for(i = 0; i< nSize; ++i) { if( !isspace( sStr[i] ) ) { nSPos = i ; break; } } for(i = nSize -1 ; i >= 0 ; --i) { if( !isspace( sStr[i] ) ) { nEPos = i; break; } } return string(sStr, nSPos, nEPos - nSPos + 1); }
źródło
W przypadku spacji wiodących i końcowych, co powiesz na:
string string_trim(const string& in) { stringstream ss; string out; ss << in; ss >> out; return out; }
Albo o zdanie:
string trim_words(const string& sentence) { stringstream ss; ss << sentence; string s; string out; while(ss >> s) { out+=(s+' '); } return out.substr(0, out.length()-1); }
źródło
void trimLeftTrailingSpaces(string &input) { input.erase(input.begin(), find_if(input.begin(), input.end(), [](int ch) { return !isspace(ch); })); } void trimRightTrailingSpaces(string &input) { input.erase(find_if(input.rbegin(), input.rend(), [](int ch) { return !isspace(ch); }).base(), input.end()); }
źródło
Nie
boost
, nieregex
, tylkostring
biblioteka. To takie proste.string trim(const string s) { // removes whitespace characters from beginnig and end of string s const int l = (int)s.length(); int a=0, b=l-1; char c; while(a<l && ((c=s.at(a))==' '||c=='\t'||c=='\n'||c=='\v'||c=='\f'||c=='\r'||c=='\0')) a++; while(b>a && ((c=s.at(b))==' '||c=='\t'||c=='\n'||c=='\v'||c=='\f'||c=='\r'||c=='\0')) b--; return s.substr(a, 1+b-a); }
źródło
W rzeczywistości jest to prostszy przypadek niż uwzględnienie wielu wiodących i końcowych znaków odstępu. Wszystko, co musisz zrobić, to usunąć zduplikowane sąsiednie znaki odstępu z całego ciągu.
Predykat dla sąsiednich białych znaków wyglądałby po prostu:
auto by_space = [](unsigned char a, unsigned char b) { return std::isspace(a) and std::isspace(b); };
a następnie możesz pozbyć się tych zduplikowanych sąsiednich znaków białych za pomocą
std::unique
i idiomu erase-remove:// s = " This is a sample string " s.erase(std::unique(std::begin(s), std::end(s), by_space), std::end(s)); // s = " This is a sample string "
To potencjalnie pozostawia dodatkowy znak odstępu z przodu i / lub z tyłu. Można to dość łatwo usunąć:
if (std::size(s) && std::isspace(s.back())) s.pop_back(); if (std::size(s) && std::isspace(s.front())) s.erase(0, 1);
Oto demo .
źródło
Moje rozwiązanie tego problemu nie używa żadnych metod STL, ale tylko własne metody C ++ stringów jest następujące :
void processString(string &s) { if ( s.empty() ) return; //delete leading and trailing spaces of the input string int notSpaceStartPos = 0, notSpaceEndPos = s.length() - 1; while ( s[notSpaceStartPos] == ' ' ) ++notSpaceStartPos; while ( s[notSpaceEndPos] == ' ' ) --notSpaceEndPos; if ( notSpaceStartPos > notSpaceEndPos ) { s = ""; return; } s = s.substr(notSpaceStartPos, notSpaceEndPos - notSpaceStartPos + 1); //reduce multiple spaces between two words to a single space string temp; for ( int i = 0; i < s.length(); i++ ) { if ( i > 0 && s[i] == ' ' && s[i-1] == ' ' ) continue; temp.push_back(s[i]); } s = temp; }
Użyłem tej metody do przekazania problemu LeetCode Reverse Words in a String
źródło
void TrimWhitespaces(std::wstring& str) { if (str.empty()) return; const std::wstring& whitespace = L" \t"; std::wstring::size_type strBegin = str.find_first_not_of(whitespace); std::wstring::size_type strEnd = str.find_last_not_of(whitespace); if (strBegin != std::wstring::npos || strEnd != std::wstring::npos) { strBegin == std::wstring::npos ? 0 : strBegin; strEnd == std::wstring::npos ? str.size() : 0; const auto strRange = strEnd - strBegin + 1; str.substr(strBegin, strRange).swap(str); } else if (str[0] == ' ' || str[0] == '\t') // handles non-empty spaces-only or tabs-only { str = L""; } } void TrimWhitespacesTest() { std::wstring EmptyStr = L""; std::wstring SpacesOnlyStr = L" "; std::wstring TabsOnlyStr = L" "; std::wstring RightSpacesStr = L"12345 "; std::wstring LeftSpacesStr = L" 12345"; std::wstring NoSpacesStr = L"12345"; TrimWhitespaces(EmptyStr); TrimWhitespaces(SpacesOnlyStr); TrimWhitespaces(TabsOnlyStr); TrimWhitespaces(RightSpacesStr); TrimWhitespaces(LeftSpacesStr); TrimWhitespaces(NoSpacesStr); assert(EmptyStr == L""); assert(SpacesOnlyStr == L""); assert(TabsOnlyStr == L""); assert(RightSpacesStr == L"12345"); assert(LeftSpacesStr == L"12345"); assert(NoSpacesStr == L"12345"); }
źródło
A co z idiomem kasuj-usuń ?
std::string s("..."); s.erase( std::remove(s.begin(), s.end(), ' '), s.end() );
Przepraszam. Za późno zauważyłem, że nie chcesz usuwać wszystkich białych znaków.
źródło