0

目前我有代码,它基于CultureInfo cultureInfo = new CultureInfo("ja-JP")a 使用

bool found = cultureInfo.CompareInfo.IndexOf(x, y,
    CompareOptions.IgnoreCase | 
    CompareOptions.IgnoreKanaType | 
    CompareOptions.IgnoreWidth
) >= 0;

由于做 ax.IndexOf(y)速度更快,而且我的xes 很多而且很少改变,我想规范化xes 一次,并在执行搜索时做一个简单的

canonicalizedX.indexOf(canonicalize(y));

我的问题:.net 库中是否有任何东西可以使用我的和来实现该canonicalize()功能?CultureInfoCompareOptions

4

2 回答 2

1

您基本上是在问:“.NET 是否给了我一种将片假名映射到平假名和全宽到半宽的方法,以便我可以进行快速比较?” 答案是响亮的不。您必须自己实施。

这是相当困难的。.NET 中的字符串比较由相当广泛的字符比较表驱动。然而,它们针对比较而不是字符替换进行了优化。通过查看源代码,您可以了解 CLR 执行此操作的方式。下载 SSCLI20 发行版并查看 clr\src\classlibnative\nls\sortingtable.cpp 源代码文件。NativeCompareInfo::LongCompareStringW() 函数进行比较,您会看到它使用 COMPARE_OPTIONS_IGNOREKANATYPE 和 COMPARE_OPTIONS_IGNOREWIDTH 标志。请注意它如何为假名使用特殊规则,走“慢路”。这个函数是巨大的,你可以从这个反向工程替代算法的可能性低到零,可以快速放弃它。日语正字法是复杂

如果您比较的字符串稳定,则考虑存储比较结果并重新使用它。

于 2013-06-13T10:15:26.360 回答
0

我最终使用了LCMapStringEx它,它对我来说很好用。它不是基于(任意集合)CompareOptions,而是CompareInfo.GetSortKey 文档引导我LCMapString,因此我indexOf的规范化字符串的效果应该与CultureInfo.CompareInfo.IndexOf使用硬编码产生相同的结果CompareOptions,这里称为dwMapFlags

public static string Canonicalize(string src)
{
    string localeName = "ja-JP";
    string nResult = src;

    int nLen, nSize;

    uint dwMapFlags = LCMAP_LOWERCASE | LCMAP_HIRAGANA | LCMAP_FULLWIDTH;
    IntPtr ptr, pZero = IntPtr.Zero;

    nLen = src.Length;
    nSize = LCMapStringEx(localeName, dwMapFlags, src, nLen, IntPtr.Zero, 0, pZero, pZero, pZero);
    if (nSize > 0)
    {
        nSize = nSize * sizeof(char);
        ptr = Marshal.AllocHGlobal(nSize);
        try
        {
            nSize = LCMapStringEx(localeName, dwMapFlags, src, nLen, ptr, nSize, pZero, pZero, pZero);
            if (nSize > 0) nResult = Marshal.PtrToStringUni(ptr, nSize);
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }
    }

    return nResult;
}

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int LCMapStringEx(
     string lpLocaleName,
     uint dwMapFlags,
     string lpSrcStr,
     int cchSrc,
     [Out]
     IntPtr lpDestStr,
     int cchDest,
     IntPtr lpVersionInformation,
     IntPtr lpReserved,
     IntPtr sortHandle);

private const uint LCMAP_LOWERCASE = 0x100;
private const uint LCMAP_UPPERCASE = 0x200;
private const uint LCMAP_SORTKEY = 0x400;
private const uint LCMAP_BYTEREV = 0x800;
private const uint LCMAP_HIRAGANA = 0x100000;
private const uint LCMAP_KATAKANA = 0x200000;
private const uint LCMAP_HALFWIDTH = 0x400000;
private const uint LCMAP_FULLWIDTH = 0x800000;

我还尝试了Microsoft.VisualBasic.StrConv,它可以工作,但速度是 pinvoking 的两倍LCMapStringEx

于 2013-06-13T11:54:24.040 回答