String NUnit-如何比较包含复合Unicode字符的字符串?

String NUnit-如何比较包含复合Unicode字符的字符串?,string,unicode,localization,nunit,String,Unicode,Localization,Nunit,我正在使用NUnit v2.5来比较包含复合Unicode字符的字符串。 虽然比较本身效果很好,但表示第一个差异的插入符号似乎放错了位置 UPD:我最终得到了覆盖的EqualConstraint,它反过来调用一个自定义TextMessageWriter,因此我不再需要答案。请参阅下面的解决方案 以下是片段: 字符串s1=”ใช้งานง่าย"; 字符串s2=”ใช้งานงาย"; 断言(s1,等于(s2)); 以下是输出: Expected: "ใช้งานงาย" But was: "

我正在使用NUnit v2.5来比较包含复合Unicode字符的字符串。
虽然比较本身效果很好,但表示第一个差异的插入符号似乎放错了位置

UPD:我最终得到了覆盖的
EqualConstraint
,它反过来调用一个自定义
TextMessageWriter
,因此我不再需要答案。请参阅下面的解决方案

以下是片段:

字符串s1=”ใช้งานง่าย";
字符串s2=”ใช้งานงาย";
断言(s1,等于(s2));
以下是输出:

Expected: "ใช้งานงาย"
But was:  "ใช้งานง่าย"
------------------^
指示第一个不同字符的箭头似乎偏离了2个位置(与上面的声调标记一样多)。对于较长的字符串,这将成为一个真正的难题。
我尝试了
String.Normalize()
,但也不起作用


如何克服此问题?感谢您的帮助。请参阅下面的答案。

您应该能够使用中的代码将每个字符串转换为原始字符串的转义版本。复合字符将成为单个转义
\u
码点,而组合字符将是一系列此类转义。然后运行
对这些转义版本的字符串进行断言。

在比较Unicode字符串时,必须始终以相同的方式规范比较的两侧。对
s1
s2
进行二进制比较是不够的,因为规范等效字符串不会测试二进制等效字符串

假设存在四个平凡的规范化函数,四种规范化形式各有一个,您需要测试
NFD(s1)
NFD(s2)
的二进制等价性。无论您是在那里使用
NFD
还是
NFC
,但必须对这两个字符串执行相同的操作


对于k-compat函数,NFKD和NFKD,它们在执行字符串搜索时非常有用,因为它们以一定的精度为代价提高了召回率™“
将等于
NFKD(“TM”)
。例如,当您在文档上运行搜索时,Adobe Reader就是这样做的:它总是在k-compat模式下运行搜索,以便您的搜索有更好的机会找到内容。但是,与
NFC
NFD
不同,k-compat函数
NFKC
NFKD
会丢失信息,并且不会反转但是,通过简单的
NFD
NFC
,你总是可以回到另一个。

我想我找不到更好的答案,所以回答我自己的问题

原因。
有许多语言对字符使用非间隔修饰符。对于欧洲语言,有替换,例如,
“u”(u+0075)+“(u+00A8)=“u”(u+00FC)
。在这种情况下,@tchrist的解决方案就足够了

然而,对于复杂的书写系统,无空格修饰符是无法替代的。因此,NUnit的
TextMessageWriter.writecarteline(int不匹配)
不匹配
参数视为字节偏移量,而泰国字符串的屏幕表示可能比插入符号行的长度短(
“----^”

解决方案。
强制
writecarteline(int-mismatch)
遵守非间距修饰符,将
mismatch
值减少到该偏移之前出现的非间距修饰符的数量。
实现所有实际上仅用于调用新代码的补充类

除了泰语,我还用德瓦纳加里语和藏语测试了它。它的效果和预期的一样

还有一个陷阱。如果你像我一样通过ReSharper在Visual Studio中使用NUnit,你必须配置你的Internet Explorer的字体(不能用R#管理),以便它对泰语、德瓦纳加里语等使用适当的单间距字体

实施。

  • 继承
    TextMessageWriter
    并重写其
    DisplayStringDifferences
  • 实现您自己的
    clipeexpectedandactual
    FindMismatchPosition
    -这里需要使用非间距修改器;需要进行适当的剪裁,因为这也可能会影响非间距元素的计算
  • 继承
    EqualConstraint
    并重写其
    WriteMessageTo(MessageWriter-writer)
    ,以便使用您的MessageWriter
  • 或者,创建一个自定义包装器,用于简单调用自定义约束
  • 下面是源代码。大约80%的代码没有做任何有用的事情,但由于原始代码中的访问级别,它被包括在内

    //第1步。
    公共类ThaiMessageWriter:TextMessageWriter
    {
    /// 
    ///该方法仅是从NUnit来源获取的原始方法的副本,
    ///除了在显示插入符号行之前更改的含义。
    /// 
    ///最初传递的包含字节偏移量,而正确显示插入符号需要
    ///它以字符占位符单位计算位置。在
    ///超过或低于字符串的Unicode字符,如锐化标记或复杂脚本(泰语)
    ///  
    /// 
    /// 
    public override void DisplayStringDifferences(预期字符串、实际字符串、int不匹配、bool ignoreCase、bool剪裁)
    {
    //无需截断即可显示的最大字符串数
    int maxDisplayLength=MaxLineLength
    -前缀长度//允许使用前缀
    -2;//2个引号
    int-mistchhoffset=不匹配;
    如果(剪辑)
    MsgUtils2.clipeexpectedandactual(ref expected,ref actual,maxDisplayLength,mistchoffset);
    预期=MsgUtils.EscapeControlChars(预期);
    实际值=MsgUtils.EscapeControlChars(实际值);
    //