如何计算字符串中的唯一字符

her*_*ron 4 c# string char

假设我们有变量myString ="blabla"或mystring = 998769

myString.Length; //will get you your result

myString.Count(char.IsLetter);    //if you only want the count of letters:
Run Code Online (Sandbox Code Playgroud)

如何获得,独特的字符数?我的意思是"blabla"结果必须是3,doe"998769"它将是4.是否准备好了功能?有什么建议?

Mar*_*zek 18

您可以使用LINQ:

var count = myString.Distinct().Count();
Run Code Online (Sandbox Code Playgroud)

它使用了一个string实现的事实IEnumerable<char>.

没有LINQ,您可以在Distinct内部执行相同的操作并使用HashSet<char>:

var count = (new HashSet<char>(myString)).Count;
Run Code Online (Sandbox Code Playgroud)


Adr*_*tti 5

如果你只处理英文的ANSI文本(或BMP中的字符),那么如果你写的话,那么80%的时间:

myString.Distinct().Count()
Run Code Online (Sandbox Code Playgroud)

你会过得很开心,也不会有任何麻烦.让我发布这个答案只是为了真正需要以正确的方式处理它.我会说每个人都应该,但我知道这不是真的(引自维基百科):

因为最常用的字符都在基本多语言平面中,所以代理对的处理通常没有经过彻底的测试.这会导致持续存在的漏洞和潜在的安全漏洞,即使在流行且经过良好评估的应用软件中也是如此(例如CVE-2008-2938,CVE-2012-2135)

的问题,我们的第一个天真的解决方案是,它不处理Unicode正确,它也不会考虑哪些用户所认为的性格.让我们试试"".Distinct().Count()你的代码将错误地返回... 2因为它的UTF-16表示是0xD840 0xDC11(BTW中的每一个,单独,不是有效的Unicode字符,因为它们分别是高和低代理).

在这里,我对术语和定义不会非常严格,所以请参考www.unicode.org作为参考.有关(更多)更广泛的讨论,请阅读如何通过字符比较执行Unicode识别字符?,编码不仅是你必须考虑的问题.

1)它没有考虑到.NET System.Char不表示字符(或更具体地一个字形),但一个代码单元一的UTF-16编码的文本(可能的,例如,与表意字符).它们经常重合,但现在总是如此.

2)如果您计算哪些用户认为(或识别)作为一个字符,然后因为这会再次失败,它不检查组合字符就像ا́在阿拉伯语的这个(许多例子).出于历史原因存在重复项:例如é,它既是单个Unicode代码点又是组合(然后该代码将失败).

3)我们谈论的是西方/美国人的性格定义.如果您为最终用户计算字符,您可能需要将您的定义更改为他们期望的内容(例如,在韩语中,字符定义可能不那么明显,另一个示例是捷克语文本ch总是被视为单个字符) .最后,当你将字符转换为大写/小写时,不要忘记一些奇怪的事情(例如在德语中ßSS大写的,也参见这篇文章).

编码

C#字符串编码为UTF-16(char两个字节),但UTF-16不是固定大小的编码,char应该正确地称为代码单元.这是什么意思?你可能有一个string地方Length是2,但实际上,用户将看到(这实际上是)一个字符(再算上应为1).

如果你需要妥善处理这个问题,那么你必须让事情变得更加复杂(而且速度慢).幸运的是,Char类有一些有用的方法来处理代理.

以下代码未经测试(为了说明的目的,所以绝对没有优化,我确信它可以做得比这更好)所以把它作为进一步调查的起点:

int CountCharacters(string text)
{
    HashSet<string> characters = new HashSet<string>();

    string currentCharacter = "";

    for (int i = 0; i < text.Length; ++i)
    {
        if (Char.IsHighSurrogate(text, i))
        {
            // Do not count this, next one will give the full pair
            currentCharacter = text[i].ToString();
            continue;
        }
        else if (Char.IsLowSurrogate(text, i))
        {
            // Our "character" is encoded as previous one plus this one
            currentCharacter += text[i];
        }
        else
            currentCharacter = text[i].ToString();

        if (!characters.Contains(currentCharacter))
            characters.Add(currentCharacter);
    }

    return characters.Count;
}
Run Code Online (Sandbox Code Playgroud)

请注意,此示例不处理重复项(当相同的字符可能具有不同的代码或可以是单个代码点或组合字符时).

组合字符

如果你必须处理组合字符(当然还有编码),那么最好的方法就是使用StringInfo类.您将枚举(然后计算)组合字符和编码字符:

StringInfo.GetTextElementEnumerator(text).Walk()
    .Distinct().Count();
Run Code Online (Sandbox Code Playgroud)

Walk()是微不足道的实施,仅仅扩展方法通过所有IEnumerator元素(我们需要它,因为GetTextElementEnumerator()收益IEnumerator代替IEnumerable).

请注意,在正确拆分文本之后,可以使用我们的第一个解决方案来计算(重点是brick不是char一系列的char(为了简单起见,这里返回string).再次,此代码不处理重复.

文化

你没有太多办法来处理第3点列出的问题.每种语言都有自己的规则并且支持它们都可能很痛苦.关于这个较长的特定职位的文化问题的更多例子.

重要的是要了解它们(所以你必须对你所针对的语言有所了解)并且不要忘记Unicode和很少翻译的resx文件不会使你的应用程序全局化.

如果文本处理在您的应用程序中很重要,您可以使用专门的DLL为您支持的每个语言环境(计算字符,计算单词等)解决许多问题,就像Word处理器一样.例如,我列出的问题可以使用词典简单地解决.我通常做的是不对字符串使用标准.NET函数(也因为一些错误),我创建了一个带有静态方法的Unicode类,用于我需要的一切(字符计数,转换,比较)和每个特殊的派生类.支持的语言.在运行时,静态方法将使用当前线程文化名称从字典中选择适当的实现并将工作委托给它.骨架可能是这样的:

abstract class Unicode
{
    public static string CountCharacters(string text)
    {
        return GetConcreteClass().CountCharactersCore(text);
    }

    protected virtual string CountCharactersCore(string text)
    {
        // Default implementation, overridden in derived classes if needed
        return StringInfo.GetTextElementEnumerator(text).Cast<string>()
            .Distinct().Count();
    }

    private Dictionary<string, Unicode> _implementations;

    private Unicode GetConcreteClass()
    {
        string cultureName = Thread.Current.CurrentCulture.Name;

        // Check if concrete class has been loaded and put in dictionary
        ...

        return _implementations[cultureName];
    }
}
Run Code Online (Sandbox Code Playgroud)