如何从字符串中删除标点符号?


70

对于这个问题,希望在30秒内获得答案,我专门在寻找C#

但是在一般情况下,在任何语言中去除标点符号的最佳方法是什么?

我应该补充:理想情况下,解决方案不需要您枚举所有可能的标点符号。

相关:Python中的标点符号


实际上,不同的语言是不同的,并且我认为您所提出的问题没有答案。您可以询问特定的语言,或者哪种语言最适合这种操作。
David Thornley 2010年

Answers:



21

为什么不简单地:

字符串s =“ sxrdct?fvzguh,bij。”;
var sb = new StringBuilder();

foreach(s中的char c)
{
   如果(!char.IsPunctuation(c))
      sb.Append(c);
}

s = sb.ToString();

RegEx的使用通常比简单的char操作要慢。这些LINQ操作对我来说似乎太过分了。而且您不能在.NET 2.0中使用此类代码...


请注意,这种方法还允许您将标点符号替换为(例如)空白。对于标记化很有用。

14

假设“最佳”的意思是“最简单的”,我建议使用如下所示的内容:

String stripped = input.replaceAll("\\p{Punct}+", "");

这个例子是针对Java的,但是所有足够现代的Regex引擎都应该支持这个(或类似的东西)。

编辑:Unicode感知版本将是这样的:

String stripped = input.replaceAll("\\p{P}+", "");

第一个版本仅查看ASCII中包含的标点符号。


1
C#没有Punct该类,但确实有该类P
JProgrammer

14

描述意图,最容易阅读(IMHO)和最佳表现:

 s = s.StripPunctuation();

实现:

public static class StringExtension
{
    public static string StripPunctuation(this string s)
    {
        var sb = new StringBuilder();
        foreach (char c in s)
        {
            if (!char.IsPunctuation(c))
                sb.Append(c);
        }
        return sb.ToString();
    }
}

这是使用Hades32的算法,该算法在发布的代码中表现最好。


有趣的花絮:以下不是标点符号:$ ^ + | <> =
Brian Low,2010年

9

您可以使用regex.replace方法:

 replace(YourString, RegularExpressionWithPunctuationMarks, Empty String)

由于此操作返回一个字符串,因此您的方法将如下所示:

 string s = Regex.Replace("Hello!?!?!?!", "[?!]", "");

如果需要,可以用更复杂的名称替换“ [?!]”:

(\p{P})

这应该找到任何标点符号。


+1用于使用unicode字符类。简洁,精确,美观。
汤姆·安德森

6

这个线程太旧了,但是我不愿发布一个更优雅的(IMO)解决方案。

string inputSansPunc = input.Where(c => !char.IsPunctuation(c)).Aggregate("", (current, c) => current + c);

是LINQ,没有WTF。


4

基于GWLlosa的想法,我能够提出极其丑陋的方法,但是可以进行以下工作:

string s = "cat!";
s = s.ToCharArray().ToList<char>()
      .Where<char>(x => !char.IsPunctuation(x))
      .Aggregate<char, string>(string.Empty, new Func<string, char, string>(
             delegate(string s, char c) { return s + c; }));

2
我知道; 对?我的爱好是对Linq中的代码犯下罪行。但是,请务必使它变得更好。
汤姆·里特

4
请寻求精神病学帮助。
汤姆·安德森

长度是s的二次方;如果您双击长度,代码会比较慢四倍,因为字符串+运营商必须使字符串的副本:/
克莱门特

3

最死脑筋的简单方法是使用string.replace

我想像的另一种方式是regex.replace,并在其中带有所有适当标点符号的正则表达式。


2

这是使用linq的稍微不同的方法。我喜欢AviewAnew的,但这避免了汇总

        string myStr = "Hello there..';,]';';., Get rid of Punction";

        var s = from ch in myStr
                where !Char.IsPunctuation(ch)
                select ch;

        var bytes = UnicodeEncoding.ASCII.GetBytes(s.ToArray());
        var stringResult = UnicodeEncoding.ASCII.GetString(bytes);

为什么IEnumerable<char>要将数组转换为字节到字符串,为什么不new String(s.ToArray())呢?还是无论如何,新的弦乐到底会做什么?
克里斯·马里西奇

2

如果要使用它来标记文本,可以使用:

new string(myText.Select(c => char.IsPunctuation(c) ? ' ' : c).ToArray())

2

对于任何想通过RegEx做到这一点的人:

这段代码显示了完整的RegEx替换过程,并提供了一个样本Regex,该Regex仅在字符串中保留字母,数字和空格-用空字符串替换所有其他字符:

//Regex to remove all non-alphanumeric characters
System.Text.RegularExpressions.Regex TitleRegex = new 
System.Text.RegularExpressions.Regex("[^a-z0-9 ]+", 
System.Text.RegularExpressions.RegexOptions.IgnoreCase);

string ParsedString = TitleRegex.Replace(stringToParse, String.Empty);

return ParsedString;


1

我遇到了同样的问题,并且担心为每个检查调用IsPunctuation会对性能产生影响。

我发现了这篇文章:http : //www.dotnetperls.com/char-ispunctuation

沿线:char.IsPunctuation还在ASCII之上处理Unicode。该方法匹配一堆包括控制字符的字符。通过定义,此方法笨重且昂贵。

最重要的是,由于它对我的ETL流程的性能影响,我最终没有这样做。

我去了dotnetperls的自定义实现。

提示一下,这是从前面的答案中得出的一些代码,以获取所有标点符号的列表(不包括对照组):

var punctuationCharacters = new List<char>();

        for (int i = char.MinValue; i <= char.MaxValue; i++)
        {
            var character = Convert.ToChar(i);

            if (char.IsPunctuation(character) && !char.IsControl(character))
            {
                punctuationCharacters.Add(character);
            }
        }

        var commaSeparatedValueOfPunctuationCharacters = string.Join("", punctuationCharacters);

        Console.WriteLine(commaSeparatedValueOfPunctuationCharacters);

干杯,安德鲁


0
#include<string>
    #include<cctype>
    using namespace std;

    int main(int a, char* b[]){
    string strOne = "H,e.l/l!o W#o@r^l&d!!!";
    int punct_count = 0;

cout<<"before : "<<strOne<<endl;
for(string::size_type ix = 0 ;ix < strOne.size();++ix)   
{   
    if(ispunct(strOne[ix])) 
    {
            ++punct_count;  
            strOne.erase(ix,1); 
            ix--;
    }//if
}
    cout<<"after : "<<strOne<<endl;
                  return 0;
    }//main

0

对于长字符串,我使用以下代码:

var normalized = input
                .Where(c => !char.IsPunctuation(c))
                .Aggregate(new StringBuilder(),
                           (current, next) => current.Append(next), sb => sb.ToString());

与使用字符串连接相比,其性能要好得多(尽管我同意它不太直观)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.