比较 char 忽略大小写的正确方法是啥?

Posted

技术标签:

【中文标题】比较 char 忽略大小写的正确方法是啥?【英文标题】:What is the correct way to compare char ignoring case?比较 char 忽略大小写的正确方法是什么? 【发布时间】:2022-01-22 06:50:49 【问题描述】:

我想知道比较两个忽略大小写的字符的正确方法适用于所有文化。另外,Comparer<char>.Default 是在不忽略大小写的情况下测试两个字符的最佳方法吗?这对代理对有效吗?

编辑:添加示例IComparer<char> 实现

如果这对任何人有帮助,这就是我决定使用的方法

public class CaseInsensitiveCharComparer : IComparer<char> 
    private readonly System.Globalization.CultureInfo ci;
    public CaseInsensitiveCharComparer(System.Globalization.CultureInfo ci) 
        this.ci = ci;
    
    public CaseInsensitiveCharComparer()
        : this(System.Globalization.CultureInfo.CurrentCulture)  
    public int Compare(char x, char y) 
        return Char.ToUpper(x, ci) - Char.ToUpper(y, ci);
    


// Prints 3
Console.WriteLine("This is a test".CountChars('t', new CaseInsensitiveCharComparer()));

【问题讨论】:

ToUpper 可能会将 char 转换为相对于当前区域性的正确大写,但返回的词法顺序不正确。可能这仅在 .NET 中支持用于字符串比较。 【参考方案1】:

这取决于您所说的“为所有文化工作”是什么意思。即使在土耳其,您是否希望“i”和“I”相等?

你可以使用:

bool equal = char.ToUpperInvariant(x) == char.ToUpperInvariant(y);

...但是根据您对“有效”的理解,我不确定根据所有文化是否“有效”。

当然,您可以将两个字符都转换为字符串,然后对字符串执行任何您想要的比较。效率稍低,但它确实为您提供了框架中可用的所有比较范围:

bool equal = x.ToString().Equals(y.ToString(), 
                                 StringComparison.InvariantCultureIgnoreCase);

对于代理对,Comparer&lt;char&gt; 无论如何都不可行,因为您没有单个 char。你可以创建一个Comparer&lt;int&gt;

【讨论】:

这就是我在您的两个示例中都考虑过的方式,但认为可能存在框架提供的更好的方式,而我不知道存在这种方式。我在考虑 String.Contains(char, IEqualityComparer) 的 LINQ 扩展方法的上下文 这里没有框架方法:字符串比较实际上是使用本地方法实现的,而不是通过下拉到一个 Comparer 实现。 @TimSchmelter:不,由于某种原因设法错过了。在末尾添加了一个快速注释。【参考方案2】:

据我了解,实际上没有一种方法可以“适用于所有文化”。您想要比较字符是出于某种内部的、非向用户显示的原因(在这种情况下,您应该使用 InvariantCulture),或者您想要使用用户的 CurrentCulture。显然,使用用户当前的文化意味着您将在不同的语言环境中获得不同的结果,但它们将与您在这些语言环境中的用户的期望保持一致。

如果不知道为什么要比较两个字符,我无法真正建议您应该使用哪个字符。

【讨论】:

谢谢乔恩,这是一个普遍的问题,我不熟悉 unicode,我想我会在这里提出这个问题。考虑 LINQ 提供的 String.Contains(char, IEqualityComparer) 扩展方法,实现不区分大小写的正确方法是什么? 再说一次,这真的取决于数据是什么以及为什么要比较它。例如,您只是想将事物排序为某种一致的顺序,使用各种不变量比较中的任何一种都可以。如果您正在响应用户输入,您可能希望使用该用户的文化来为他们提供他们期望的结果。我不确定是否真的有“一刀切”的答案。 您认为作为答案提供的比较器实现是正确的方法吗?【参考方案3】:

我建议比较大写,如果不匹配则比较小写,以防语言环境的大写和小写逻辑表现稍有不同。

附录

例如,

int CompareChar(char c1, char c2)

    int  dif;

    dif = char.ToUpper(c1) - char.ToUpper(c2);
    if (diff != 0)
        dif = char.ToLower(c1) - char.ToLower(c2);
    return dif;

【讨论】:

【参考方案4】:

我认为在运行时中可用的内容类似于以下内容

public class CaseInsensitiveCharComparer : IComparer<char> 
    private readonly System.Globalization.CultureInfo ci;
    public CaseInsensitiveCharComparer(System.Globalization.CultureInfo ci) 
        this.ci = ci;
    
    public CaseInsensitiveCharComparer()
        : this(System.Globalization.CultureInfo.CurrentCulture)  
    public int Compare(char x, char y) 
        return Char.ToUpper(x, ci) - Char.ToUpper(y, ci);
    


// Prints 3
Console.WriteLine("This is a test".CountChars('t', new CaseInsensitiveCharComparer()));

【讨论】:

假设在未来的 CLR 版本中通过减法进行的 char 比较将继续正确是很危险的,所以我会改用 return Char.ToUpper(x, ci).CompareTo(Char.ToUpper(y, ci)); @MattHowells 我认为...请参阅char.CompareTo(char):return (m_value-value);【参考方案5】:

string.Compare("string a","STRING A",true)

它适用于每个字符串

【讨论】:

嗨,塞尔吉奥,我正在寻找一种比较两个字符实例的方法,而不是字符串实例。我正在寻找忽略大小写的 Comparer 实现。 这在英语国家非常有效。但是,东欧没有人会使用您编写的应用程序。 @Jon Grant:我在我的国家(葡萄牙)使用这个,葡萄牙语是一种基于拉丁语的语言,有很多“奇怪”的字符,比如:ãéàç,它非常适合我。 【参考方案6】:

你可以试试:

    class Test
    static int Compare(char t, char p)
        return string.Compare(t.ToString(), p.ToString(), StringComparison.CurrentCultureIgnoreCase);
    

但我怀疑这是执行此操作的“最佳”方式,但我并不是您需要检查的所有情况...

【讨论】:

【参考方案7】:

我知道这是一篇旧帖子,但从那以后情况发生了变化。

上面的问题可以通过使用扩展来回答。这将扩展 char.Equals 以允许局部性和不区分大小写。

在扩展类中,添加如下内容:

internal static Boolean Equals(this Char src, Char ch, StringComparison comp)

    Return $"src".Equals($"ch", comp);

我目前在工作,所以无法检查,但应该可以。

安迪

【讨论】:

非常糟糕的解决方案。涉及许多内存分配。【参考方案8】:

您可以为 caseInsensetive 匹配提供最后一个参数为 true

string.Compare(lowerCase, upperCase, true);

【讨论】:

以上是关于比较 char 忽略大小写的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

.NET如何比较两个代表文件名的字符串忽略大小写正确

如何让字符串数组的Contains忽略大小写

1.10 字符串比较 内容忽略大小写方法

AC日记——忽略大小写的字符串比较 openjudge 1.7 16

忽略词缀检查器的大小写[重复]

为啥sql比较忽略大小写[重复]