C ++从字符串中删除标点符号

Posted

技术标签:

【中文标题】C ++从字符串中删除标点符号【英文标题】:C++ Remove punctuation from String 【发布时间】:2013-10-02 14:10:43 【问题描述】:

我有一个字符串,我想从中删除所有标点符号。我怎么做?我做了一些研究,发现人们使用 ispunct() 函数(我试过了),但我似乎无法让它在我的代码中工作。有人有什么想法吗?

#include <string>

int main() 

string text = "this. is my string. it's here."

if (ispunct(text))
text.erase();

return 0;

【问题讨论】:

你应该一个一个检查所有字符。 【参考方案1】:

使用算法remove_copy_if :-

string text,result;
std::remove_copy_if(text.begin(), text.end(),            
                        std::back_inserter(result), //Store output           
                        std::ptr_fun<int, int>(&std::ispunct)  
                       );

【讨论】:

【参考方案2】:

如果您需要将结果作为新字符串,POW 已经有一个很好的答案。如果您想要就地更新,这个答案是如何处理它。

配方的第一部分是std::remove_if,它可以有效地去除标点符号,将所有非标点符号打包。

std::remove_if (text.begin (), text.end (), ispunct)

不幸的是,std::remove_if 不会将字符串缩小到新的大小。它不能,因为它无法访问容器本身。因此,打包结果后的字符串中会留下垃圾字符。

为了处理这个问题,std::remove_if 返回一个迭代器,指示字符串中仍需要的部分。这可以与字符串erase 方法一起使用,导致以下成语...

text.erase (std::remove_if (text.begin (), text.end (), ispunct), text.end ());

我将此称为习语,因为它是一种适用于许多情况的常用技术。 string 以外的其他类型提供合适的 erase 方法,std::remove(可能还有一些我暂时忘记的其他算法库函数)采用这种方法来缩小它们删除的项目的差距,但留下容器 -根据调用者调整大小。

【讨论】:

我刚试过,我得到一个错误:“候选模板被忽略:无法推断模板参数'_Predicate' remove_if(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred)” @moonman239 - 我的猜测是谓词可能有不止一个隐式转换 - remove_if 候选人并没有完全限制选项。可调用对象的处理在 C++14、C++17 和 C++20 中得到了发展。可能使用 lambda 作为谓词 - 要么就地,要么使用使用该 lambda 表达式初始化的auto 类型推断变量 - 因此不需要强制转换为可调用对象。不过,我最近编写的代码不多,所以如果这没有帮助,我只能建议提出一个单独的问题。【参考方案3】:
#include <string>
#include <iostream>
#include <cctype>

int main() 

    std::string text = "this. is my string. it's here.";

    for (int i = 0, len = text.size(); i < len; i++)
    
        if (ispunct(text[i]))
        
            text.erase(i--, 1);
            len = text.size();
        
    

    std::cout << text;
    return 0;

输出

this is my string its here

当您删除一个字符时,字符串的大小会发生变化。每当发生删除时,都必须更新它。而且,您删除了当前字符,因此下一个字符成为当前字符。如果不减少循环计数器,则不会检查标点字符旁边的字符。

【讨论】:

我无法编译 ispunct。我已经包含了你所做的所有标题。 您必须包含&lt;ctype.h&gt;&lt;cctype&gt;【参考方案4】:

ispunct 采用 char 值而不是字符串。

你可以这样做

for (auto c : string)
     if (ispunct(c)) text.erase(text.find_first_of(c));

这可行,但它是一个缓慢的算法。

【讨论】:

text.erase()?你确定吗?【参考方案5】:

Steve314 的回答非常好。 我想补充一点:

text.erase (std::remove_if (text.begin (), text.end (), ::ispunct), text.end ());

在函数 ispunct 之前添加 :: 负责重载。

【讨论】:

【参考方案6】:

这里的问题是 ispunct() 将一个参数作为一个字符,而您正在尝试发送一个字符串。您应该遍历字符串的元素并删除每个字符,如果它是像这里这样的标点符号:

for(size_t i = 0; i<text.length(); ++i)
  if(ispunct(text[i]))
    text.erase(i--, 1);

【讨论】:

【参考方案7】:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() 
    string str = "this. is my string. it's here.";

    transform(str.begin(), str.end(), str.begin(), [](char ch)
    
        if( ispunct(ch) )
            return '\0';
        return ch;
    );

【讨论】:

【参考方案8】:

您可以这样做的另一种方法如下:

#include <ctype.h> //needed for ispunct()
string onlyLetters(string str)
    string retStr = "";

    for(int i = 0; i < str.length(); i++)
        if(!ispunct(str[i]))
            retStr += str[i];
        
    
    return retStr;

这最终会创建一个新字符串,而不是实际从旧字符串中删除字符,但它比使用一些更复杂的内置函数更容易理解。

【讨论】:

【参考方案9】:
 #include <iostream>
 #include <string>

 using namespace std;

 int main()
 
   string s;//string is defined here.

  cout << "Please enter a string with punctuation's: " << endl;//Asking for users input

  getline(cin, s);//reads in a single string one line at a time

/* ERROR Check: The loop didn't run at first because a semi-colon was placed at the end 
                of the statement.  Remember not to add it for loops. */
        for(auto &c : s)  //loop checks every character 
               
             if (ispunct(c)) //to see if its a punctuation
              
               c=' ';       //if so it replaces it with a blank space.(delete) 
              

        

        cout <<  s << endl; 


   system("pause");
   return 0;
   

【讨论】:

【参考方案10】:

我尝试应用 @Steve314 的答案,但直到我在 cppreference.com 上看到此注释 here 后才能让它发挥作用:

备注

&lt;cctype&gt; 中的所有其他函数一样,std::ispunct 的行为 如果参数的值既不能表示为 unsigned char 也不等于 EOF。为了安全地使用这些功能 普通chars(或signed chars),首先要转换参数 到unsigned char

通过研究它提供的示例,我可以使它像这样工作:

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

int main()

    std::string text = "this. is my string. it's here.";
    std::string result;
    text.erase(std::remove_if(text.begin(),
                              text.end(),
                              [](unsigned char c)  return std::ispunct(c); ),
               text.end());
    std::cout << text << std::endl;

【讨论】:

【参考方案11】:

尝试使用这个,它将删除文本文件中字符串上的所有标点符号。

str.erase(remove_if(str.begin(), str.end(), ::ispunct), str.end());

如果有帮助请回复

【讨论】:

【参考方案12】:

我明白了。

size_t found = text.find('.');
text.erase(found, 1);

【讨论】:

这只会删除'.'的第一个实例,它不会删除所有标点符号和'.'的所有实例。 您应该编辑您的答案,以免误导他人。但它也只删除了 '.'....不是所有的标点符号。

以上是关于C ++从字符串中删除标点符号的主要内容,如果未能解决你的问题,请参考以下文章

如何从 C 字符串中删除第一个字符?

从c中的链表中删除名称时出错

从字符串 C 中删除 char

★c语言★如何删除字符串中的第一位?★

从C#目录中删除转义序列

从C中的字符串中删除空格