Nice programing

문자열에서 선행 및 후행 공백 제거

nicepro 2020. 10. 22. 22:45
반응형

문자열에서 선행 및 후행 공백 제거


C ++의 문자열 개체에서 공백을 제거하는 방법.
예를 들어, 아래 문자열 객체에서 선행 및 후행 공백을 제거하는 방법.

//Original string: "         This is a sample string                    "
//Desired string: "This is a sample string"

내가 아는 한 문자열 클래스는 선행 및 후행 공백을 제거하는 방법을 제공하지 않습니다.

문제를 추가하려면이 서식을 확장하여 문자열의 단어 사이에 추가 공백을 처리하는 방법입니다. 예를 들면

// Original string: "          This       is         a sample   string    " 
// Desired string:  "This is a sample string"  

솔루션에 언급 된 문자열 메서드를 사용하여 이러한 작업을 두 단계로 수행하는 것을 생각할 수 있습니다.

  1. 선행 및 후행 공백을 제거하십시오.
  2. 원하는 형식을 얻으려면 단어 경계에서 find_first_of, find_last_of, find_first_not_of, find_last_not_of 및 substr 을 반복적으로 사용하십시오 .

이를 트리밍이라고합니다. Boost 를 사용할 수 있다면 추천합니다.

그렇지 않으면을 사용 find_first_not_of하여 공백이 아닌 첫 번째 문자 find_last_not_of의 인덱스를 가져온 다음 공백이 아닌 끝에서 인덱스를 가져옵니다. 이를 사용 substr하여 주변 공백이없는 하위 문자열을 가져옵니다.

당신의 편집에 대한 응답으로, 나는 용어를 모르지만 "축소"라는 줄을 따라 무언가를 추측 할 것입니다. 그래서 그것을 제가 부르는 것입니다. :) (참고, 유연성을 위해 공백을 매개 변수로 변경했습니다.)

#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 ""; // no content

    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")
{
    // trim first
    auto result = trim(str, whitespace);

    // replace sub ranges
    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;
}

결과:

[too much               space]  
[too much space]  
[too-much-space]  
[one  
two]  

한 줄로 std :: string에서 선행, 후행 및 추가 공백을 쉽게 제거

value = std::regex_replace(value, std::regex("^ +| +$|( ) +"), "$1");

선행 공백 만 제거

value.erase(value.begin(), std::find_if(value.begin(), value.end(), std::bind1st(std::not_equal_to<char>(), ' ')));

또는

value = std::regex_replace(value, std::regex("^ +"), "");

후행 공백 만 제거

value.erase(std::find_if(value.rbegin(), value.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), value.end());

또는

value = std::regex_replace(value, std::regex(" +$"), "");

여분의 공백 만 제거

value = regex_replace(value, std::regex(" +"), " ");

현재 다음 기능을 사용하고 있습니다.

// 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);
}

부스트 스트링 트림 알고리즘

#include <boost/algorithm/string/trim.hpp>

[...]

std::string msg = "   some text  with spaces  ";
boost::algorithm::trim(msg);

방법은 다음과 같습니다.

std::string & trim(std::string & str)
{
   return ltrim(rtrim(str));
}

그리고 지원 기능은 다음과 같이 구현됩니다.

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;   
}

이 모든 것이 제자리에 있으면 다음과 같이 작성할 수 있습니다.

std::string trim_copy(std::string const & str)
{
   auto s = str;
   return ltrim(rtrim(s));
}

이 시도


부스트를 사용하라는 jon-hanson의 제안에 따라 선행 및 후행 공백을 자르는 예 (후행 및 보류중인 공백 만 제거) :

#include <boost/algorithm/string/trim.hpp>

std::string str = "   t e s t    ";

boost::algorithm::trim ( str );

결과 "t e s t"

도 있습니다

  • trim_left 결과 "t e s t "
  • trim_right 결과 " t e s t"

이것은 선행 및 후행 공백을 제거하는 솔루션입니다 ...

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);

결과는 "Plamen"입니다.


/// 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);
}

위 코드에서 isSpace () 함수는 문자가 공백인지 여부를 알려주는 부울 함수입니다.이 함수를 구현하여 필요를 반영하거나 원하는 경우 "ctype.h"에서 isspace ()를 호출 할 수 있습니다. .


표준 라이브러리를 사용하면 많은 이점이 있지만 예외를 발생시키는 몇 가지 특별한 경우를 알고 있어야합니다. 예를 들어, C ++ 문자열에 유니 코드 문자가있는 경우에 대한 답변은 없습니다. 이 경우 isspace 함수를 사용하면 예외가 발생합니다.

다음 코드를 사용하여 문자열 및 유용한 기타 작업을 다듬 었습니다. 이 코드의 주요 이점은 다음과 같습니다. 정말 빠르며 (내가 테스트 한 어떤 코드보다 빠름) 표준 라이브러리 만 사용하며 예외가 발생하지 않습니다.

#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;
    }
}

선행 및 후행 공백 자르기의 예

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);

또는

trimmedSring = aString.substr(aString.find_first_not_of(' '), (aString.find_last_not_of(' ') - aString.find_first_not_of(' ')) + 1);

나는 이것을 테스트했으며 모두 작동합니다. 따라서 processInput 메소드는 사용자에게 무언가를 입력하도록 요청합니다. 내부적으로 추가 공백이없고 시작 또는 끝에 추가 공백이없는 문자열을 반환합니다. 도움이 되었기를 바랍니다. (또한 이해하기 쉽도록 많은 주석을 추가하십시오).

하단의 main ()에서 구현하는 방법을 볼 수 있습니다.

#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;
}

이것은 가장 간단한 것일 수 있습니다.

당신은 사용할 수 있습니다 string::findstring::rfind양쪽에서 공백 발견하고 문자열을 줄일 수 있습니다.

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);
    }
}

왜 복잡합니까?

std::string removeSpaces(std::string x){
    if(x[0] == ' '){ x.erase(0, 1); }
    if(x[x.length()-1] == ' '){ x.erase(x.length()-1, x.length()); }
    return x;
}

부스트가 실패하고 정규식이없고 이상한 물건이나 라이브러리가 없어도 작동합니다.


    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);

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());
}

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);
}

선행 및 후행 공백의 경우 다음은 어떻습니까?

string string_trim(const string& in) {

    stringstream ss;
    string out;
    ss << in;
    ss >> out;
    return out;

}

또는 문장 :

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);
}

청초한

 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());
    }

아니 boost, 아니 regex, 그냥 string도서관. 그렇게 간단합니다.

string trim(const string s) { // removes whitespace characters from beginnig and end of string s
    string x = s;
    for(int i=0; i<(int)s.length(); i++) {
        const int l = (int)x.length()-1;
        if(x[l]==' '||x[l]=='\t'||x[l]=='\n'||x[l]=='\v'||x[l]=='\f'||x[l]=='\r'||x[l]=='\0') x.erase(l, 1);
        if(x[0]==' '||x[0]=='\t'||x[0]=='\n'||x[0]=='\v'||x[0]=='\f'||x[0]=='\r'||x[0]=='\0') x.erase(0, 1);
    }
    return x;
}

무엇에 대한 삭제 - 제거 관용구 ?

std::string s("...");
s.erase( std::remove(s.begin(), s.end(), ' '), s.end() );

죄송합니다. 공백을 모두 제거하고 싶지 않다는 것을 너무 늦게 보았습니다 .


STL 메서드를 사용하지 않고 C ++ 문자열 자체 메서드 만 사용하는이 문제에 대한 내 솔루션은 다음과 같습니다.

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;
}

이 방법을 사용하여 LeetCode 문제를 전달 했습니다. 문자열에서 단어 반전


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");
}

참고 URL : https://stackoverflow.com/questions/1798112/removing-leading-and-trailing-spaces-from-a-string

반응형