【问题标题】:string.equals giving false positives [duplicate]string.equals 给出误报[重复]
【发布时间】:2017-04-07 18:46:24
【问题描述】:

在将事件存储到事件管理系统中时,我还存储了更改的历史记录。因为项目指定使用 MySql,而 MySql 触发器有一些不足之处,所以我使用实际代码来检测更改。我有以下代码行来查看支持备注字段是否更改,并相应地添加历史记录:

    ....
    if (!String.Equals(OldEventInfo.supportNotes, NewEventInfo.supportNotes))
    {  ChangesMade.Add(new EventHistoryDataItem("support notes", OldEventInfo.supportNotes, NewEventInfo.supportNotes)); }
    ....
    EventsDataset eds = new EventsDataset();
    EventsDatasetTableAdapters.eventhistoryTableAdapter ehta = new EventsDatasetTableAdapters.eventhistoryTableAdapter();
    EventsDatasetTableAdapters.eventhistorydataTableAdapter ehdta = new EventsDatasetTableAdapters.eventhistorydataTableAdapter();
    Int64 HistoryId = Convert.ToInt64(ehta.InsertQuery(NewEventInfo.id.Value, DateTime.Now, UserId));

    eds.eventhistorydata.Clear();
    foreach (EventHistoryDataItem thisChange in ChangesMade)
    {
        EventsDataset.eventhistorydataRow newRow = (EventsDataset.eventhistorydataRow)eds.eventhistorydata.NewRow();
        newRow.eventHistoryId = HistoryId;
        newRow.field = thisChange.Field;
        newRow.oldValue = thisChange.OldValue;
        newRow.newValue = thisChange.NewValue;
        eds.eventhistorydata.AddeventhistorydataRow(newRow);
    }
    ehdta.Update(eds.eventhistorydata);

问题是我得到的“支持说明”的历史记录在前后具有相同的值。我已经查看了关于 SO 的其他关于 string.equals 生成错误返回的问题,并且我已经检查以确保之前和之后的字符串是相同的,并且它们是相同的。没有多余的空格或回车或换行符。它们是二进制相同的。

那么,什么给了?在我的历史记录中,值已从 A 更改为 B,但 A 和 B 相同的记录是如何结束的?

【问题讨论】:

  • 我知道你说没有空格或回车。但空格和回车并不是唯一无法呈现的字符。还有许多编辑无法渲染的字符。确认没有多余字符的一种方法是包含长度测试:if( OldEventInfo.supportNotes.Length != NewEventInfo.supportNotes.Length && !String.Equals(OldEventInfo.supportNotes, NewEventInfo.supportNotes)) { ... }
  • 如果它们是二进制相同的,那么它们的 GetHashCode() 应该返回相同的值。如果不是,那么无论出于何种原因,它们都不相等(例如行尾不同或沿着这些行)。
  • @StephenPorter - 事实证明,你是对的,这意味着我撒了谎。我回去仔细看了一下,果然琴弦不一样。在数据进入 Unix 服务器上的 MySql 和返回之间的某个地方,Windows 换行符(回车 + 换行符 - 0D0A)变成了 Unix 换行符(换行符 - 0A)。这导致字符串测试不相等。
  • 我可能会在稍后删除这个问题。原来是stackoverflow.com/q/25999031/4843530的副本
  • @AgapwIesu 很好,很高兴你明白了 :) 当我开始使用 .NET Core 时,我遇到了这个问题,因为我在 Windows 中开发、Docker 化我的应用程序并部署到 Linux 服务器。你遇到了行尾和路径问题哈哈。

标签: c# asp.net string dataset


【解决方案1】:

这是因为字符串编码不同,它们的字符串不相等,尽管它们包含相同的字符。

如果你想比较两个字符串并且它们来自不同的来源,并且你不担心编码,那么使用 string.Normalize() 方法比较它们就可以了。

【讨论】:

  • Michael,你知道 string.Normalize 对 New-Line 的平台特定实现有什么作用吗?我在谷歌上搜索并找到了很多关于 Unicode 规范化的文章,但没有什么能告诉我换行符会发生什么。
  • 并非如此。您可以模拟一个快速控制台应用程序,将不同版本的文本解析为各种二进制编码并对其进行测试。我很好奇……
  • 好建议。我自己应该想到的。我做了这样一个模型,并且 Normalize 保留了回车和换行符。回车和换行都存在于 UTF-16 中,这是 c# 字符串使用的,所以我猜它认为这两个字符都是“正常”的 unicode。但我不确定我是否真的理解 Unicode 规范化的概念。无论如何,感谢您帮助我了解这一点。我敢打赌它会派上用场的。
【解决方案2】:

所以字符串确实不同。 小心二进制比较表明,在一个版本的字符串中有回车,而在另一个版本中没有。我不得不直接从数据库中提取数据来比较它们......

select hex(OldValue), hex(NewValue) from EventHistoryData where Id = 39645;

这表明在应该有换行符的地方,字符串的一个版本具有换行符的 Windows 实现 (CarriageReturn + LineFeed = \r\n = x0D0A),而另一个版本的 Unix 实现为换行符(LifeFeed = \n = x0A)。 在我的 Windows IIS 机器和 Unix 机器上的 MySql 服务器之间的某个地方,字符串的换行符正在转换为 Unix 实现。

最简单的解决方案是更改比较以忽略回车。由于 Windows 换行符是 \r\n 而 Unix 和 Mac 换行符是 \n,比较字符串时最简单的做法是删除 \r,将所有换行符转换为 Unix 版本。所以

if (!String.Equals(OldEventInfo.supportNotes, NewEventInfo.supportNotes))

变成

if (!String.Equals(OldEventInfo.supportNotes.Replace("\r",""), NewEventInfo.supportNotes.Replace("\r","")))

【讨论】:

    猜你喜欢
    • 2020-10-30
    • 2011-08-13
    • 2014-04-18
    • 2015-08-02
    • 2022-01-21
    • 2014-08-18
    • 1970-01-01
    • 2015-10-02
    相关资源
    最近更新 更多