如何在C ++字符串中分隔数字和字母?

时间:2014-10-22 07:38:43

标签: c++ string algorithm c++11 gcc

我有几个包含数字和字母的输入字符串。有时空间不足。每当字符串从数字变为字母或从字母变为数字时,我想添加一个额外的空格。

示例输入:

"30EinsteinStreet"
"548 Roe Drive5500 TestCity"
"44B SaarlouisDrive1234Testtown"

他们应该成为:

"30 EinsteinStreet"
"548 Roe Drive 5500 TestCity"
"44 B SaarlouisDrive 1234 Testtown"

我现有的功能不起作用,我认为很复杂。有人能提供简单的解决方案吗?最好使用现代C ++ 11类,但不使用Boost。我也在使用GCC所以所有正则表达式的东西对我都不起作用。

由于

这是我现有的方法:

        inline string separateAlphanumChunks(const std::string& s) 
        {
            string ret = "";
            const int sl = s.length();
            //int inserts = 0;

            if (sl<=4)
                return s;

            for (int i=0 ; i< sl ; i++)
            {
//              cerr << "separateAlphanumChunks: '" << ret << "'" <<endl;
                // check if index would go out of range
                if (i+4 > sl)
                {
                    ret += s.substr (i,sl-i);
                    //TODO add the remain to ret
                    break;
                }

                // seperate chars
                const char c0 = s[i+0];
                const char c1 = s[i+1];

                // check if 0 and 1 are the same class
                const bool c0c = isCharAnInt (c0);
                const bool c1c = isCharAnInt (c1);
                bool class0 = false;
                if (c0c == c1c)
                {
                    class0 = c0c;
                }
                else
                {
                    ret += c0;
//                  cerr << "cont1: '" << c0 << "'" <<endl;
                    continue;
                }

                // seperate chars
                const char c2 = s[i+2];
                const char c3 = s[i+3];

                // check if 2 and 3 are the same class
                const bool c2c = isCharAnInt (c2);
                const bool c3c = isCharAnInt (c3);
                bool class2 = false;
                if (c2c == c3c)
                {
                    class2 = c2c;
                }
                else
                {
                    ret += c0;
//                  cerr << "cont2: '" << c0 << "'" <<endl;
                    continue;
                }

                // check if the 2 classes are different
                if (class0 != class2)
                {
                    // split!
                    ret += c0+(c1+string(" ")+c2)+c3;
                    //inserts++;
                    i+=3;
                }
                else
                {
                    ret += c0;
//                  cerr << "cont3: '" << c0 << "'" <<endl;
                    continue;
                }

            }

            // remove double spaces
            //replaceStringInPlace(ret, "  "," "); 
            //cerr << "separateAlphanumChunks: '" << ret << "'" <<endl;
            return ret;
        }

    inline bool isCharAnInt (char c)
    {
        //TODO might be able to use isdigit() here
        int i = c - '0';
        return ((i>=0) && (i<=9));
    }

6 个答案:

答案 0 :(得分:2)

我看到了各种复杂的答案,这也是给出另一个答案的原因。 您的问题的答案恰好在问题陈述中: &#34;每次字符串从数字变为字母或从字母变为数字时添加额外的空格。&#34;

所以这正是你想要的(我使用了之前答案中的一些代码)编译应该使用标志-std = c ++ 11

完成
#include <string>
#include <iostream>
using namespace std;

enum charTypeT{ other, alpha, digit};

charTypeT charType(char c){
    if(isdigit(c))return digit;
    if(isalpha(c))return alpha;
    return other;
}

string separateThem(string inString){
  string oString = "";charTypeT st=other;
    for(auto c:inString){
        if( (st==alpha && charType(c)==digit) || (st==digit && charType(c)==alpha) )
          oString.push_back(' ');
        oString.push_back(c);st=charType(c);
    }
    return oString;
}

int main(){
  string str1 = "30EinsteinStreet";
  string str2 = "548 Roe Drive5500 TestCity";
  string str3 = "44B SaarlouisDrive1234Testtown";

  cout << separateThem(str1) << endl;
  cout << separateThem(str2) << endl;
  cout << separateThem(str3) << endl;
}

答案 1 :(得分:1)

我认为你在寻找什么以及Ajay所暗示的是解析字符串的finite-state machine。 虽然这不是C ++ 11解决方案,您可以通过正则表达式找到更优雅的解决方案,但我提供了下面的代码示例。

#include <iostream>
#include <sstream>

bool isDigit(const char c)
{
    bool res = true;
    switch (c)
    {
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
            break;

        default:
            res = false;
            break;
    }
    return res;
}

std::string separateNumbers(const std::string& inputString)
{
    const size_t N = inputString.length();
    std::ostringstream os;
    bool readDigit = false;
    for (size_t i = 0; i < N; ++i)
    {
        if (isDigit(inputString[i]))
        {
            if ((i > 0) && (i < N) && (! readDigit))
            {
                if (inputString[i] != ' ')
                    os << ' ';
            }
            readDigit = true;
        }
        else
        {
            if ((i > 0) && (i < N) && (readDigit))
            {
                if (inputString[i] != ' ')
                    os << ' ';
            }
            readDigit = false;
        }
        os << inputString[i];
    }
    return os.str();
}

int main(int argc, char** argv)
{
    std::string strings[3] = {
        "30EinsteinStreet",
        "548 Roe Drive5500 TestCity",
        "44B SaarlouisDrive1234Testtown"
    };

    for (int i = 0; i < 3; ++i)
    {
        std::cout << "input #" << i << ": " << strings[i] << std::endl;
        std::cout << "output #" << i << ": " << separateNumbers(strings[i]) << std::endl;
        std::cout << std::endl;
    }

    return 0;
}

答案 2 :(得分:1)

这是我的五美分。

#include <iostream>
#include <string>
#include <cctype>

std::string SeparateAlphanumChunks( const std::string &s )
{
    std::string::size_type n = 0;
    bool ctype = std::isdigit( s[0] );

    for ( char c : s )
    {
        if ( !ctype != !std::isdigit( c ) )
        {
            ctype = std::isdigit( c );
            if ( !isblank( c ) ) ++n;
        }
    }

    std::string t;
    t.reserve( s.size() + n );

    ctype = std::isdigit( s[0] );

    for ( char c : s )
    {
        if ( !ctype != !std::isdigit( c ) )
        {
            ctype = std::isdigit( c );
            if ( !isblank( c ) ) t.push_back( ' ');
        }
        t.push_back( c );
    }

    return t;
}

int main() 
{
    for ( const std::string &s : { "30EinsteinStreet",
                                   "548 Roe Drive5500 TestCity",
                                   "44B SaarlouisDrive1234Testtown" 
                                 } )
    {
        std::cout << SeparateAlphanumChunks( s ) << std::endl;
    }

    return 0;
}

输出

30 EinsteinStreet
548 Roe Drive 5500 TestCity
44 B SaarlouisDrive 1234 Testtown

您也可以“就地”更改字符串。例如

#include <iostream>
#include <string>
#include <cctype>

std::string & SeparateAlphanumChunks( std::string &s )
{
    std::string::size_type n = 0;
    bool ctype = std::isdigit( s[0] );

    for ( char c : s )
    {
        if ( !ctype != !std::isdigit( c ) )
        {
            ctype = std::isdigit( c );
            if ( !isblank( c ) ) ++n;
        }
    }

    s.reserve( s.size() + n );

    ctype = std::isdigit( s[0] );

    for ( std::string::size_type i = 0; i < s.size(); i++ )
    {
        if ( !ctype != !std::isdigit( s[i] ) )
        {
            ctype = std::isdigit( s[i] );
            if ( !isblank( s[i] ) ) 
            {
                s.insert( i, 1, ' ' );
            }
        }
    }

    return s;
}


int main() 
{
    for ( std::string s : { "30EinsteinStreet",
                            "548 Roe Drive5500 TestCity",
                                "44B SaarlouisDrive1234Testtown" 
                              } )
    {
        std::cout << SeparateAlphanumChunks( s ) << std::endl;
    }

    return 0;
}

答案 3 :(得分:1)

我建议通过迭代字符串元素。 这样的事情会有所帮助:

#include <string>
#include <iostream>
using namespace std;

string separateThem(string inString){
  string numbers = "1234567890";
  string oString = "";
  int i;
  for(i=0; i<inString.size()-1; i++){
    if ((numbers.find(inString[i]) != string::npos) && (numbers.find(inString[i+1]) == string::npos) && !isspace(inString[i+1])){
      oString += inString.substr(i,1) + " ";
    }
    else if ((numbers.find(inString[i]) == string::npos) && (numbers.find(inString[i+1]) != string::npos) && !isspace(inString[i+1])){
      oString += inString.substr(i,1) + " ";
    }
else oString += inString.substr(i,1);
  }
  oString += inString.substr(i,1);
  return oString;
}

int main(){
  string str1 = "30EinsteinStreet";
  string str2 = "548 Roe Drive5500 TestCity";
  string str3 = "44B SaarlouisDrive1234Testtown";

  cout << separateThem(str1) << endl;
  cout << separateThem(str2) << endl;
  cout << separateThem(str3) << endl;
}

如果执行此操作,输出将为:

30 EinsteinStreet
548 Roe Drive 5500 TestCity
44 B SaarlouisDrive 1234 Testtown

希望这会有所帮助:)

答案 4 :(得分:1)

升级到GCC 4.9(其第一个版本已于4月发布)并使用简单的正则表达式:

#include <regex>
#include <iostream>

std::string fix(const std::string& in)
{
    return std::regex_replace(
        in,
        std::regex("(?:([a-zA-Z])([0-9]))|(?:([0-9])([a-zA-Z]))"),
        "\\1\\3 \\2\\4",
        std::regex_constants::format_sed
    );
}

int main()
{
    const std::string in[] = {
        "30EinsteinStreet",
        "548 Roe Drive5500 TestCity",
        "44B SaarlouisDrive1234Testtown"
    };

    for (auto el : in)
        std::cout << fix(el) << '\n';
}

/*
"30 EinsteinStreet"
"548 Roe Drive 5500 TestCity"
"44 B SaarlouisDrive 1234 Testtown"
*/

live demo

答案 5 :(得分:0)

我建议你将string迭代为原始字符串(即string::c_str()),并完全生成一个新字符串。这将是我的算法(不是很完整):

  • 对于每个字符,请检查它是否为数字。如果不是,只需附加到新字符串。
  • 如果是,请检查它是否是第一个字符 - 如果是,只需附加到新字符串。
  • 如果数字是最后一个字符,则附加到新字符串。
  • 如果数字介于两者之间,请检查最后添加的字符是否为空格。如果没有空间,请放一个空格,然后放数字。
  • 如果最后插入的字符是数字,并且这也是数字,请插入。
  • 但是,如果last是数字,但这不是数字(而不是空格),则插入空格。

您可能需要进一步调整它。

如果字符串是这样的:

"enter 144    code   here    123    "