0

現在、コードをCultureInfo cultureInfo = new CultureInfo("ja-JP")使用して検索を行うコードがあります

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

aを実行するx.IndexOf(y)方がはるかに高速であり、私のxesは十分にあり、めったに変更されないため、esを一度正規化したいと思いxます。検索を実行するときは簡単です

canonicalizedX.indexOf(canonicalize(y));

私の質問: myとcanonicalize()を使用して関数を実装できる .net ライブラリに何かありますか?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ため、正規化された文字列の my の効果は、ここで呼ばれるハードコードされた を使用してindexOfと同じ結果をもたらすはずです:CultureInfo.CompareInfo.IndexOfCompareOptionsdwMapFlags

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 の 2 倍の速度ですLCMapStringEx

于 2013-06-13T11:54:24.040 に答える