2

日本語の形態アナライザーMeCabをC#プログラム(Visual Studio 2010 Express、Windows 7)で使用しようとしていますが、エンコードに問題があります。私の入力(テキストボックスに貼り付けられた)がこれである場合:

猫、広義の「ネコ」は、ネコ科(ネコ科動物)の動物、性的との獣をとなると、とされる。</ pre>

次に、(別のテキストボックス内の)出力は次のようになります。

?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
(å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
)å詞、サ変接続、*、*、*、*、*
?å詞、サ変接続、*、*、*、*、*
????????????????????????? å詞、サ変接続、*、*、*、*、*
EOS

これは、他のエンコーディングのテキストがUTF-8でエンコードされたテキストと間違えられていると思います。ただし、EUC-JPであり、Encoding.Convertを使用してUTF-8に変換しても、出力は変更されません。Shift-JISであると仮定し、同じことを行うと、異なるジブリッシュが発生します。また、テキストを確実に処理している間(MeCab出力がフォーマットされることになっている方法です)、入力をUTF-8として解釈しているようにも見えません。そうすると、出力に1文字の「化合物」で始まる同一の行がすべて含まれるわけではなく、明らかに識別できません。

MeCabのコマンドラインで文を実行すると、さらに別の見た目のジブリッシュが発生します。ただし、繰り返しになりますが、これは左下にある1つの疑問符と括弧の列にすぎないため、Windowsコマンドラインが日本語のフォントをサポートしていないという問題だけではありません。繰り返しになりますが、入力をUTF-8として読み込んでいないだけです。(MeCabをUTF-8モードでインストールしました。)

コードの関連部分は次のようになります。

[DllImport( "libmecab.dll"、CallingConvention = CallingConvention.Cdecl)]
private extern static IntPtr mecab_new2(string arg);
[DllImport( "libmecab.dll"、CallingConvention = CallingConvention.Cdecl)]
[戻り値:MarshalAs(UnmanagedType.AnsiBStr)]
private extern static string mecab_sparse_tostr(IntPtr m、string str);
[DllImport( "libmecab.dll"、CallingConvention = CallingConvention.Cdecl)]
private extern static void mecab_destroy(IntPtr m);

プライベート文字列meCabParse(string jpnText)
{{
    IntPtr mecab = mecab_new2( "");
    文字列parsedText=mecab_sparse_tostr(mecab、jpnText);

    mecab_destroy(mecab);
    parsedTextを返します。
}

(もっともらしいものをいじって違いが生じるかどうかを確認するという観点から、「UnmanagedType.AnsiBStr」を「UnmanagedType.BStr」に切り替えてみました。これにより、「AccessViolationException was unhandled」というエラーが発生し、「CharSet = CharSet.Unicode」をDllImportパラメーターに変換します。これにより、出力が「EOS」になります。)

これが私が変換を行ってきた方法です:

// 65001 = UTF-8コードページ、20932=EUC-JPコードページ
プライベート文字列convertEncoding(string sourceString、int sourceCodepage、int targetCodepage)
{{
    エンコーディングsourceEncoding=Encoding.GetEncoding(sourceCodepage);
    エンコーディングtargetEncoding=Encoding.GetEncoding(targetCodepage);

    //ソース文字列をバイト配列に変換します
    byte [] sourceBytes = sourceEncoding.GetBytes(sourceString);

    //それらのバイトをターゲットエンコーディングに変換します
    byte [] targetBytes = Encoding.Convert(sourceEncoding、targetEncoding、sourceBytes);

    //バイト配列からchar配列
    char [] targetChars = new char [targetEncoding.GetCharCount(targetBytes、0、targetBytes.Length)];

    //char配列からtargtでエンコードされた文字列
    targetEncoding.GetChars(targetBytes、0、targetBytes.Length、targetChars、0);
    string targetString = new string(targetChars);

    targetStringを返します。
}

プライベート文字列meCabParse(string jpnText)
{{
    //テキストを文字列からUTF-8からEUC-JPに変換します
    jpnText = convertEncoding(jpnText、65001、20932);

    IntPtr mecab = mecab_new2( "");
    文字列parsedText=mecab_sparse_tostr(mecab、jpnText);

    //annndをUTF-8に変換し直します
    parsedText = convertEncoding(parsedText、20932、65001);

    mecab_destroy(mecab);
}

提案/挑発?

4

1 に答える 1

2

私は同じことをする方法を探しているこのスレッドに出くわしました。私はあなたのコードを出発点として使用し、このブログ投稿はUTF8文字列をマーシャリングする方法を理解するために使用しました。

次のコードは、適切にエンコードされた出力を提供します。

public class Mecab
{
    [DllImport("libmecab.dll", CallingConvention = CallingConvention.Cdecl, CharSet=CharSet.Unicode)]
    private extern static IntPtr mecab_new2(string arg);
    [DllImport("libmecab.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    private extern static IntPtr mecab_sparse_tostr(IntPtr m, byte[] str);
    [DllImport("libmecab.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    private extern static void mecab_destroy(IntPtr m);

    public static String Parse(String input)
    {
        IntPtr mecab = mecab_new2("");
        IntPtr nativeStr = mecab_sparse_tostr(mecab, Encoding.UTF8.GetBytes(input));
        int size = nativeArraySize(nativeStr) - 1;
        byte[] data = new byte[size];
        Marshal.Copy(nativeStr, data, 0, size);

        mecab_destroy(mecab);

        return Encoding.UTF8.GetString(data);
    }

    private static int nativeArraySize(IntPtr ptr)
    {
        int size = 0;
        while (Marshal.ReadByte(ptr, size) > 0)
            size++;

        return size;
    }
}
于 2011-06-20T13:35:05.293 に答える