【问题标题】:Unexpected behavior with StartsWith and unicodeStartsWith 和 unicode 的意外行为
【发布时间】:2021-05-17 21:30:18
【问题描述】:

在处理一个问题时,我遇到了一个有趣的用例。 StartsWith 方法(可能还有其他一些方法)在以下两种情况下返回 true:

"\u0000Example".StartsWith("Example");          // returns true
"\u0000Example".StartsWith("\u0000Example");    // returns true

包含此示例和单元测试的存储库:https://github.com/DeanMilojevic/UnicodeInvestigation

由于我没有时间深入研究该方法的实现,我想知道这是一个“错误”还是预期的行为?

否则,当我在空闲时间发现更多信息时,会用更多信息更新问题。

【问题讨论】:

  • 这是另一个数据点:"\u0000Example".StartsWith("Example", StringComparison.Ordinal)
  • 另外,请注意,这在 .NET 5 中发生了变化,这强烈表明它与从 NLS 到 ICU 的转变有关
  • @canton7 我对此也有同样的感觉。当我找到一些时间时,正计划调试并查看某一时刻发生了什么。我正在考虑是否也可以在 GitHub 上提交票证。

标签: c# asp.net-core


【解决方案1】:

.NET 5 中引入的一项重大更改是从 Windows 上的 NLS to ICU 全球化库的转换。我在您的帖子中没有看到任何提及,但假设您使用的是 .NET 5,那么这种行为似乎不是错误。

引用docs

如果您使用 string.IndexOf(string) 之类的函数而不调用采用 StringComparison 参数的重载,您可能打算执行序数搜索,但您无意中依赖于特定于文化的行为。 由于 NLS 和 ICU 在其语言比较器中实现了不同的逻辑,因此 string.IndexOf(string) 等方法的结果可能会返回意外值。

如果您查看this table,您会发现string.StartsWith 方法在传递字符串参数时默认使用CurrentCulture 比较。由于您正在进行 culture-specific 比较(通过不指定 StringComparison 参数),那么 ICU 库似乎忽略了空 unicode 字符 \u0000而 NLS 库似乎没有。

从您的代码来看,您想要做的似乎是执行序数搜索,可以使用:"\u0000Example".StartsWith("Example", StringComparison.Ordinal) 正确返回 false

建议在您的项目中启用code analyzers,以帮助您识别在可能打算使用序数比较器时意外使用语言比较器的代码。

建议启用的规则是:

CA1307: Specify StringComparison for clarity

CA1309: Use ordinal StringComparison

CA1310: Specify StringComparison for correctness

要启用这些代码分析规则并让它们导致构建错误,只需将以下内容添加到您的项目文件中:

<PropertyGroup>
  <AnalysisMode>AllEnabledByDefault</AnalysisMode>
  <WarningsAsErrors>$(WarningsAsErrors);CA1307;CA1309;CA1310</WarningsAsErrors>
</PropertyGroup>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-11
    • 2017-03-27
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多