C#字符串比较等于false

本文关键字:false 比较 字符串 | 更新日期: 2023-09-27 18:21:43

我有一个字符串比较问题,在大多数情况下,它的行为与预期的一样,但由于我的代码没有检测到字符串对是重复的,所以给我留下了大量重复的DB插入。

我以为我已经把它缩小到了一个文化问题(西里尔字母),我解决了这个问题,但我现在得到了"假阴性"(两个明显相等的字符串显示为不相等)。

我研究了以下类似的问题,并尝试了以下比较方法。

我检查过的类似SO问题:

  • 为什么我的比较总是返回false
  • C#字符串相等运算符返回false,但I';我很确定这应该是真的。。。什么
  • 即使C#中的两个字符串相同,String Equals()方法也会失败
  • C中字符串比较方法的差异#

下面是一个比较字符串的例子:(标题和描述)

提要标题:埃尔斯伯格:他是英雄

消息来源:丹尼尔·埃尔斯伯格告诉CNN的唐·莱蒙,美国国家安全局泄密者爱德华·斯诺登表现出了勇气,做了巨大的服务。

db标题:Ellsberg:他是英雄

数据库描述:Daniel Ellsberg告诉CNN的Don Lemon,美国国家安全局泄密者Edward Snowden表现出了勇气做了大量的服务。

我的应用程序将从RSS提要中获取的值与我在数据库中的值进行比较,并且应该只插入"新"值。

//fetch existing articles from DB for the current feed:
    List<Article> thisFeedArticles = (from ar in entities.Items
                                      where (ar.ItemTypeId == (int)Enums.ItemType.Article) && ar.ParentId == feed.FeedId
                                      && ar.DatePublished > datelimit
                                      select new Article
                                      {
                                           Title = ar.Title, 
                                           Description = ar.Blurb
                                      }).ToList();

以下比较中的每个人都无法与埃尔斯伯格的头衔/描述相匹配。即匹配1到匹配6都具有Count()==0

(请原谅列举的变量名-它们只是为了测试)

   // comparison methods 
CompareOptions compareOptions = CompareOptions.OrdinalIgnoreCase;
CompareOptions compareOptions2 = CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace;
//1
IEnumerable<Article> matches = thisFeedArticles.Where(b =>
    String.Compare(b.Title.Trim().Normalize(), a.Title.Trim().Normalize(), CultureInfo.InvariantCulture, compareOptions) == 0 &&
    String.Compare(b.Description.Trim().Normalize(), a.Description.Trim().Normalize(), CultureInfo.InvariantCulture, compareOptions) == 0
    );
//2
IEnumerable<Article> matches2 = thisFeedArticles.Where(b =>
    String.Compare(b.Title, a.Title, CultureInfo.CurrentCulture, compareOptions2) == 0 &&
    String.Compare(b.Description, a.Description, CultureInfo.CurrentCulture, compareOptions2) == 0
    );
//3
IEnumerable<Article> matches3 = thisFeedArticles.Where(b =>
    String.Compare(b.Title, a.Title, StringComparison.OrdinalIgnoreCase) == 0 &&
    String.Compare(b.Description, a.Description, StringComparison.OrdinalIgnoreCase) == 0
    );
//4
IEnumerable<Article> matches4 = thisFeedArticles.Where(b =>
    b.Title.Equals(a.Title, StringComparison.OrdinalIgnoreCase) &&
    b.Description.Equals(a.Description, StringComparison.OrdinalIgnoreCase)
    );
//5
IEnumerable<Article> matches5 = thisFeedArticles.Where(b =>
    b.Title.Trim().Equals(a.Title.Trim(), StringComparison.InvariantCultureIgnoreCase) &&
    b.Description.Trim().Equals(a.Description.Trim(), StringComparison.InvariantCultureIgnoreCase)
    );
//6
IEnumerable<Article> matches6 = thisFeedArticles.Where(b =>
    b.Title.Trim().Normalize().Equals(a.Title.Trim().Normalize(), StringComparison.OrdinalIgnoreCase) &&
    b.Description.Trim().Normalize().Equals(a.Description.Trim().Normalize(), StringComparison.OrdinalIgnoreCase)
    );

    if (matches.Count() == 0 && matches2.Count() == 0 && matches3.Count() == 0 && matches4.Count() == 0 && matches5.Count() == 0 && matches6.Count() == 0 && matches7.Count() == 0)
    {
    //insert values
    }
    //this if statement was the first approach
    //if (!thisFeedArticles.Any(b => b.Title == a.Title && b.Description == a.Description)
    // {
    // insert
    // }

显然,我一次只使用了上述选项中的一个。

在大多数情况下,上述选项确实有效,大多数重复项都被检测到,但仍有重复项从裂缝中溜走——我只需要了解"裂缝"是什么,所以任何建议都是最受欢迎的。

我甚至尝试过将字符串转换为字节数组并对其进行比较(抱歉,前一段时间删除了该代码)。

Article对象如下:

    public class Article
    {
        public string Title;
        public string Description;
    }

更新:

我已经尝试过规范化字符串以及包括IgnoreSymbols CompareOption,但我仍然得到一个假阴性(不匹配)。不过,我注意到的是,撇号似乎在虚假的不匹配中一致出现;所以我认为这可能是撇号与单引号的情况,即"vs"(等等),但IgnoreSymbols肯定应该避免这种情况吗?

我发现了几个更相似的SO帖子:C#字符串比较忽略空格、回车或换行字符串比较:InvariantCultureIgnoreCase与OrdinalIgnoreCare?下一步:尝试使用regex按照以下答案去除空白:https://stackoverflow.com/a/4719009/2261245

更新2在6次比较仍然没有结果后,我意识到一定有另一个因素影响了结果,所以我尝试了以下

//7
IEnumerable<Article> matches7 = thisFeedArticles.Where(b =>
    Regex.Replace(b.Title, "[^0-9a-zA-Z]+", "").Equals(Regex.Replace(a.Title, "[^0-9a-zA-Z]+", ""), StringComparison.InvariantCultureIgnoreCase) &&
    Regex.Replace(b.Description, "[^0-9a-zA-Z]+", "").Equals(Regex.Replace(a.Description, "[^0-9a-zA-Z]+", ""), StringComparison.InvariantCultureIgnoreCase)
    );

这确实找到了其他人错过的比赛!

下面的字符串通过了所有6个比较,但没有通过第7个:

a.Title.Trim().Normalize()a.Title.Trim()都返回:

"勘误表:一种独特的TGF-β依赖性分子和小胶质细胞的功能特征"

DB中的值为:

"勘误表:一种独特的TGF-ß依赖性分子和小胶质细胞的功能特征"

更仔细的检查表明,与提要中的内容相比,DB中的德语"eszett"字符有所不同:βvsß

我本以为1-6中至少有一个会得到这个结果。。。

有趣的是,经过一些性能比较,Regex选项决不是七个选项中最慢的。Normalize似乎比正则表达式更密集!以下是当thisFeedArticles对象包含12077个项目时,所有七个项目的Stopwatch持续时间

经过时间:00:00:00.0000662
经过时间:00:00:00.0000009
经过时间:00:00:00.0000009
经过时间:00:00:00.0000009
经过时间:00:00:00.0000009
经过时间:00:00:00.0000009
经过时间:00:00:00.000016

C#字符串比较等于false

Unicode字符串可以是"二进制"的不同,即使它们在"语义上"相同。

试着规范化你的字符串。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/System.String.Normalize.aspx