使用CultureInfo和CompareOptions对字符串进行规范化

时间:2013-06-13 08:10:00

标签: .net globalization

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

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

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

canonicalizedX.indexOf(canonicalize(y));

我的问题:我可以使用.net库中的任何内容,使用我的canonicalize()CultureInfo实现CompareOptions函数吗?

2 个答案:

答案 0 :(得分:1)

你基本上都在问:“.NET是否让我有办法将片假名映射到hirigana,全宽到半宽,这样我就能进行快速比较?”答案是响亮的。你必须自己实现。

这很难。 .NET中的字符串比较由相当广泛的字符比较表驱动。然而,它们被优化用于比较,而不是用于字符替换。通过查看源代码,您可以了解CLR执行此操作的方式。下载SSCLI20发行版并查看clr \ src \ classlibnative \ nls \ sortingtable.cpp源代码文件。 NativeCompareInfo :: LongCompareStringW()函数进行比较,您将看到它使用COMPARE_OPTIONS_IGNOREKANATYPE和COMPARE_OPTIONS_IGNOREWIDTH标志。请注意它如何使用Kana的特殊规则,采取“慢速路径”。这个函数是大量的,你可以从这个反向设计替换算法的几率足够低到零,以便快速提供。日语拼写复杂

如果你比较的字符串是稳定的,那么考虑存储比较结果并重新使用它。

答案 1 :(得分:0)

我最终使用LCMapStringEx,它对我来说很好。它不是基于(任意一组)CompareOptions,而CompareInfo.GetSortKey docs引导我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,但它的工作速度是LCMapStringEx的两倍。