2011-06-16 70 views
2

我试图在C#程序(Visual Studio 2010 Express,Windows 7)中使用日语形态分析器MeCab,并且出现了编码错误。如果我的输入(粘贴到文本框)是这样的:试图让libmecab.dll(MeCab)与C一起工作#

一方、広義の「ネコ」は、ネコ類(ネコ科動物)の一部、あるいはその全ての獣を指す包括的名称を指す。

然后我输出(在另一个文本)看起来是这样的:

 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
( åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
) åè©ž,サ変接続,*,*,*,*,* 
? åè©ž,サ変接続,*,*,*,*,* 
????????????????????????? åè©ž,サ変接続,*,*,*,*,* 
EOS 

我猜想,这是在其他一些编码是错误的文字用于UTF-8编码的文本。但假设它是EUC-JP并使用Encoding.Convert将它变成UTF-8不会改变输出;假设它是Shift-JIS,并且执行相同的操作会产生不同的乱码。另外,尽管它确实处理文本 - 这就是MeCab输出如何格式化 - 但它似乎并没有将输入解释为UTF-8。如果这样做的话,输出中不会出现所有那些以单字符“化合物”开始的相同行,而这显然无法识别。

当我通过MeCab的命令行运行这个句子时,我又得到了另外一个不同寻常的乱码。但是,再一次,它只是一排单个问号和左边的括号,所以这不仅仅是Windows命令行不支持带有日文字符的字体的问题;再一次,它只是没有以UTF-8格式读取输入内容。 (我没有在UTF-8模式下安装仲裁处)。

代码的相关部分是这样的:

 
[DllImport("libmecab.dll", CallingConvention = CallingConvention.Cdecl)] 
private extern static IntPtr mecab_new2(string arg); 
[DllImport("libmecab.dll", CallingConvention = CallingConvention.Cdecl)] 
[return: 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); 

private string meCabParse(string jpnText) 
{ 
    IntPtr mecab = mecab_new2(""); 
    string parsedText = mecab_sparse_tostr(mecab, jpnText); 

    mecab_destroy(mecab); 
    return parsedText; 
} 

(与合理的前瞻性的东西摆弄方面,看看他们是否有所作为,我尝试将“UnmanagedType.AnsiBStr”切换为“UnmanagedType.BStr”,它给出错误“AccessViolationException was unhandled”,并将“CharSet = CharSet.Unicode”添加到DllImport参数中,这会将输出转换为“EOS “)

这就是我一直在做的转换:

 
// 65001 = UTF-8 codepage, 20932 = EUC-JP codepage 
private string convertEncoding(string sourceString, int sourceCodepage, int targetCodepage) 
{ 
    Encoding sourceEncoding = Encoding.GetEncoding(sourceCodepage); 
    Encoding targetEncoding = Encoding.GetEncoding(targetCodepage); 

    // convert source string into byte array 
    byte[] sourceBytes = sourceEncoding.GetBytes(sourceString); 

    // convert those bytes into target encoding 
    byte[] targetBytes = Encoding.Convert(sourceEncoding, targetEncoding, sourceBytes); 

    // byte array to char array 
    char[] targetChars = new char[targetEncoding.GetCharCount(targetBytes, 0, targetBytes.Length)]; 

    //char array to targt-encoded string 
    targetEncoding.GetChars(targetBytes, 0, targetBytes.Length, targetChars, 0); 
    string targetString = new string(targetChars); 

    return targetString; 
} 

private string meCabParse(string jpnText) 
{ 
    // convert the text from the string from UTF-8 to EUC-JP 
    jpnText = convertEncoding(jpnText, 65001, 20932); 

    IntPtr mecab = mecab_new2(""); 
    string parsedText = mecab_sparse_tostr(mecab, jpnText); 

    // annnd convert back to UTF-8 
    parsedText = convertEncoding(parsedText, 20932, 65001); 

    mecab_destroy(mecab); 
} 

建议/嘲讽?

+0

你知道什么编码的字典?尝试运行mecab -D并查看正在使用的字符集。 – buruzaemon 2011-06-16 03:23:20

+0

它设置为使用ipadic-utf8字典。 – snarp 2011-06-18 03:43:34

回答

2

我碰到这个线程寻找一种方法来做同样的事情。我用你的代码作为起点,并且用this blog post来弄清楚如何编组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; 
    } 
} 
+0

是的!这样可行!非常感谢您发布您的解决方案。我不知道为什么我在Google上搜索时没有遇到过这个博客。 – snarp 2011-06-21 01:35:20