c ++在非字母字符上拆分字符串

Posted

技术标签:

【中文标题】c ++在非字母字符上拆分字符串【英文标题】:c++ splitting string on non alphabetic characters 【发布时间】:2014-11-13 23:11:44 【问题描述】:

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

我想使用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 认为空格有效吗?

【问题讨论】:

我从未使用过它,但find_first_not_of() 是如何工作的?应该只将指针存储为拆分位置。在传递给函数的字符串中包含大写和小写字符。 应该返回字符串中字符的位置,该位置不是指定的字符之一,但在我的情况下,它只是分成单个字符 你应该检查while( (pos=...) != npos ) 是的,已经添加了,没有它不会拆分,它会拆分成单个字符。像这样的事情可以用 Java 中的单个 3 字语句来完成 .... C++ 并不容易 啊,就像我说的我从未使用过它,也做了很多 C++。但是,如果我要击败 C++ 联盟(或女士),我会首先尝试单一、简单的用例。 pos 返回的断点/ 【参考方案1】:
#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";

Online demo

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

【讨论】:

这正是我在做什么,我的插入函数将计数设置为 1。我只调用一次搜索函数,它使用该指针返回指向节点的指针,我要么将计数加一,要么添加如果指针为空,则新节点 您的解决方案正在运行,但如果行尾没有分隔符,则不会计算最后一个单词,请删除行尾的最后一个点以了解我的意思。如果一行只有一个单词也是如此,它将被忽略。 好的,我想现在应该修复了 所以我对这两种解决方案都运行了完成时间,而这个解决方案大约快 0.003 秒或 30~ 毫秒。处理 570k 个字符的文件时,总时间约为 340-345~ ms,@sln 解决方案为 370~。【参考方案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 . . .

【讨论】:

嘿,即时拆分()!! int k 是做什么用的? 我认为使用 find_if_not 和 isalpha 作为谓词会加快速度,并且无需写出整个字母表 @Smac89 如果你有机会展示如何使用它,find_if 返回一个插入器而不是字符串中的位置, @AistisTaraskevicius,看看我的回答

以上是关于c ++在非字母字符上拆分字符串的主要内容,如果未能解决你的问题,请参考以下文章

使用 UTF-8 在非 ASCII 字符上运行 Ascii 正则表达式

在 Android 上解析查询字符串

在 Web 上显示 iOS emoji unicode 字符

Java 中文字符串比较

从 C++/CLI 应用程序将 STL 字符串传递给 C++ DLL

C/S权限系统