非字母字符上的 C++ 拆分字符串

c++ splitting string on non alphabetic characters

本文关键字:C++ 拆分 字符串 字符      更新时间:2023-10-16

我正在逐行读取文件,我想拆分非字母字符,如果可能的话,同时删除所有非字母字符,这样我就不必稍后再做。

我想使用 isalpha ,但无法弄清楚如何将其与 str.find() 或类似函数一起使用,因为这些函数通常将单个分隔符作为字符串。

    while(getline(fileToOpen,str))
    {
        unsigned int pos= 0;
        string token;
        //transform(str.begin(),str.end(),str.begin(),::tolower);
        while (pos = str.find_first_not_of("abcdefghijklmnopqrstuvwxyzQWERTYUIOPASDFGHJKLZXCVBNM"))
        {
            token = str.substr(0, pos);
            //transform(str.begin(),str.end(),str.begin(),::tolower);
            Node<t>* ptr=search(token,root);
            if (ptr!=NULL)
            {
                ptr->count++;
                cout<<token<<" already in tree.Count "<<ptr->count<<"n";
            }
            else
            {
                insert(token,root);
                cout<<token<<" added to tree.n";
            }
            ptr=NULL;
            str.erase(0, pos);
        }
    }

我的最新尝试不起作用...我能找到的所有例子都是基于str.find("single delimiter")

这对我没有好处。

找到了使用isalpha的方法

template<typename t>
void Tree<t>::readFromFile(string filename)
{
    string str;
    ifstream fileToOpen(filename.c_str());
    if (fileToOpen.is_open())
    {
        while(getline(fileToOpen,str))
        {
            unsigned int pos= 0;
            string token;
            //transform(str.begin(),str.end(),str.begin(),::tolower);
            while (pos = find_if(str.begin(),str.end(),aZCheck)!=str.end()!=string::npos)
            {
                token = str.substr(0, pos);
                transform(token.begin(),token.end(),token.begin(),::tolower);
                Node<t>* ptr=search(token,root);
                if (ptr!=NULL)
                {
                    ptr->count++;
                   // cout<<token<<" already in tree.Count "<<ptr->count<<"n";
                }
                else
                {
                    insert(token,root);
                    cout<<token<<" added to tree.n";
                }
                ptr=NULL;
                str.erase(0, pos);
            }
        }
        fileToOpen.close();
    }
    else
        cout<<"Unable to open file!n";
}
template<typename t>
inline bool Tree<t>::aZCheck(char c)
{
    return !isalpha(c);
}

但是问题仍然存在,字符串被拆分为单个字符而不是单词,并且 isalpha 认为空格是否有效?

#include <algorithm>
#include <cctype>
...
template<typename t>
void Tree<t>::readFromFile(std::string filename)
{
    std::string str;
    std::ifstream fileToOpen(filename.c_str());
    if (fileToOpen.is_open())
    {
        for (std::string::iterator pos, prev; std::getline(fileToOpen, str); )
        {                
            for (pos = std::find_if(str.begin(), str.end(), isalpha); pos != str.end();
                pos = std::find_if(prev, str.end(), isalpha))
            {
                prev = std::find_if_not(pos, str.end(), isalpha);
                std::string token(pos, prev);
                std::transform(token.begin(), token.end(), token.begin(), ::tolower);
                Node<t>* ptr = search(token, root);
                if (ptr != NULL)
                {
                    ptr->count++;
                   // cout<< token << " already in tree.Count "<<ptr->count<<"n";
                }
                else
                {
                    insert(token, root);
                    cout << token << " added to tree.n";
                }
            }
        }
        fileToOpen.close();
    }
    else
        cout<<"Unable to open file!n";
}

在线演示

另外,既然你说你想节省时间,如果你的插入函数做一些额外的事情,这将有利于你,即在树中找不到值,如果它在树中找不到,并将位置的计数器设置为 1。如果值在树中,只需递增计数器即可。这将使您免于进行 2 次迭代,因为您的树可能不平衡

试试这个测试用例。两个问题。

1 - 当在截断(或开始
)后的字符串开头找到分隔符时,Pos 为 0这导致它突破了时间。请改用npos作为条件检查。

2 - 擦除时必须将位置推进到分隔符之外,否则
它一遍又一遍地找到同一个。

    int pos= 0;
    string token;
    string str = "Thisis(asdfasdfasdf)and!this)))";
    while ((pos=str.find_first_not_of("abcdefghijklmnopqrstuvwxyzQWERTYUIOPASDFGHJKLZXCVBNM"))!= string::npos )
    {
        if ( pos != 0 )
        {
            // Found a token
            token = str.substr(0, pos);
            cout << "Found: " << token << endl;
        }
        else
        {
            // Found another delimiter
            // Just move on to next one
        }
        str.erase(0, pos+1);  // Always remove pos+1 to get rid of delimiter
    }
    // Cover the last (or only) token
    if ( str.length() > 0 )
    {
        token = str;
        cout << "Found: " << token << endl;
    }

输出>>

Found: Thisis
Found: asdfasdfasdf
Found: and
Found: this
Press any key to continue . . .