除引号外,删除字符串中的空格,转换大小写

Remove whitespace, convert case, in string except in quotes

本文关键字:空格 转换 大小写 删除 字符串      更新时间:2023-10-16

我使用的是没有Boost的c++ 03。

假设我有一个字符串,如…日期为"星期一"

我想把它处理成

THEDAYISMon天

也就是说,将不在引号内的内容转换为大写,并删除不在引号内的空白。

字符串可以不包含引号,但如果包含引号,则只有2个。

我尝试使用STL算法,但我卡住了如何记住它是否在元素之间的引号。

当然我可以用老式的for循环来实现,但我想知道是否有一种奇特的c++方法。

谢谢。

这就是我使用for循环的结果

while (getline(is, str))
{
    // remove whitespace and convert case except in quotes
    temp.clear();
    bool bInQuote = false;
    for (string::const_iterator it = str.begin(), end_it = str.end(); it != end_it; ++it)
    {
        char c = *it;
        if (c == '"')
        {
            bInQuote = (! bInQuote);
        }
        else
        {
            if (! ::isspace(c))
            {
                temp.push_back(bInQuote ? c : ::toupper(c));
            }
        }
    }
    swap(str, temp);

您可以使用STL算法做如下操作:

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;
struct convert {
   void operator()(char& c) { c = toupper((unsigned char)c); }
};
bool isSpace(char c)
{
  return std::isspace(c);
}
int main() {
    string input = "The day is "Mon Day" You know";
    cout << "original string: " << input <<endl;
    unsigned int firstQuote = input.find(""");
    unsigned int secondQuote = input.find_last_of(""");
    string firstPart="";
    string secondPart="";
    string quotePart="";
    if (firstQuote != string::npos)
    {
       firstPart = input.substr(0,firstQuote);
       if (secondQuote != string::npos)
       {
          secondPart = input.substr(secondQuote+1);
          quotePart = input.substr(firstQuote+1, secondQuote-firstQuote-1);
                                   //drop those quotes
       }
       std::for_each(firstPart.begin(), firstPart.end(), convert());
       firstPart.erase(remove_if(firstPart.begin(), 
                firstPart.end(), isSpace),firstPart.end());
       std::for_each(secondPart.begin(), secondPart.end(), convert());
       secondPart.erase(remove_if(secondPart.begin(), 
                    secondPart.end(), isSpace),secondPart.end());
       input = firstPart + quotePart + secondPart;
    }
    else //does not contains quote
    {
        std::for_each(input.begin(), input.end(), convert());
        input.erase(remove_if(input.begin(), 
                          input.end(), isSpace),input.end());
    }
     cout << "transformed string: " << input << endl;
     return 0;
}

输出如下:

original string: The day is "Mon Day" You know
transformed string: THEDAYISMon DayYOUKNOW

使用您所显示的测试用例:

original string: The day is "Mon Day"
transformed string: THEDAYISMon Day

只是为了搞笑,使用自定义迭代器,std::copystd::back_insert_iterator,以及知道跳过空白并在引号字符上设置标志的operator++:

CustomStringIt& CustomStringIt::operator++ ()
{
    if(index_<originalString_.size())
        ++index_;
    if(!inQuotes_ && isspace(originalString_[index_]))
        return ++(*this);
    if('"'==originalString_[index_])
    {
        inQuotes_ = !inQuotes_;
        return ++(*this);
    }
    return *this;
}
char CustomStringIt::operator* () const
{
    char c = originalString_[index_];
    return inQuotes_ ? c : std::toupper(c) ; 
}

您可以使用stringstreamgetline"字符作为分隔符,而不是换行符。将字符串分成三种情况:第一个引号之前的部分,引号中的部分,第二个引号之后的部分。

在添加到输出之前处理第一部分和第三部分,但添加第二部分时不进行处理。

如果字符串不包含引号,则整个字符串将包含在第一部分中。第二部分和第三部分将为空。

while (getline (is, str)) {
  string processed;
  stringstream line(str);
  string beforeFirstQuote;
  string inQuotes;
  getline(line, beforeFirstQuote, '"');
  Process(beforeFirstQuote, processed);
  getline(line, inQuotes, '"');
  processed += inQuotes;
  getline(line, afterSecondQuote, '"');
  Process(afterFirstQuote, processed);
}
void Process(const string& input, string& output) {
    for (string::const_iterator it = input.begin(), end_it = input.end(); it != end_it; ++it)
    {
      char c = *it;
        if (! ::isspace(c))
          {
            output.push_back(::toupper(c));
          }
    }
}