正在尝试使libmecab.dll(MeCab)与C#一起使用
本文关键字:一起 MeCab dll libmecab | 更新日期: 2023-09-27 17:59:27
我正试图在C#程序(Visual Studio 2010学习版,Windows 7)中使用日语形态分析器MeCab,但编码出现问题。如果我的输入(粘贴到文本框中)是这样的:
一方、広義の「ネコ」は、ネコ類(ネコ科動物)の一部、あるいはその全ての獣を指す包括的名称を指す。
然后我的输出(在另一个文本框中)看起来是这样的:
?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž**?ågellicž*?ågellicž*?ågellicž*?ågellicž*?ågellicž*)ågellicž*?ågellicž*?????????????????????????ågellicž*EOS
我想这是其他编码中的文本被误认为是UTF-8编码的文本。但假设它是EUC-JP并使用Encoding.Convert将其转换为UTF-8并不会改变输出;假设它是Shift JIS,这样做会产生不同的胡言乱语。此外,虽然它肯定在处理文本——MeCab输出应该是这样格式化的——但它似乎也没有将输入解释为UTF-8。如果它这样做,输出中就不会有所有以一个字符"化合物"开头的相同行,而这显然是它无法识别的。
当我在MeCab的命令行中运行这句话时,我又听到了另一组看起来不同的胡言乱语。但是,同样,这只是一排向左的问号和括号,所以这不仅仅是Windows命令行不支持带有日语字符的字体的问题;同样,它只是没有以UTF-8的形式读取输入。(我确实以UTF-8模式安装了MeCab。)
代码的相关部分如下所示:
[DllImport("libmecab.dll",CallingConvention=CallingConversion.Cdecl)]private extern static IntPtr mecab_new2(字符串arg);[DllImport("libmecab.dll",CallingConvention=CallingConversion.Cdecl)][return:MarshalAs(UnmanagedType.AnsiBStr)]private extern静态字符串mecab_sparse_tostr(IntPtr m,字符串str);[DllImport("libmecab.dll",CallingConvention=CallingConversion.Cdecl)]私有外部静态空隙mecab_destroy(IntPtr m);私有字符串meCabParse(字符串jpnText){IntPtr mecab=mecab_new2(");string parsedText=mecab_sparse_tostr(mecab,jpnText);mecab_destroy(mecab);返回parsedText;}
(为了摆弄看似合理的东西,看看它们是否有区别,我尝试将"UnmanagedType.AnsiBStr"切换为"UnmanagedType.BStr",这会产生错误"AccessViolationException未处理",并在DllImport参数中添加"CharSet=CharSet.Unicode",这将输出变成"EOS"。)
这就是我进行转换的方式:
//65001=UTF-8代码页,20932=EUC-JP代码页private字符串convertEncoding(字符串sourceString,int sourceCodepage,int targetCodepage){编码sourceEncoding=编码.GetEncoding(sourceCodepage);Encoding targetEncoding=编码.GetEncoding(targetCodepage);//将源字符串转换为字节数组byte[]sourceBytes=sourceEncoding.GetBytes(sourceString);//将这些字节转换为目标编码byte[]targetBytes=Encoding.Convert(sourceEncoding,targetEncoding、sourceBytes);//字节数组到字符数组char[]targetChars=新char[targetEncoding.GetCharCount(targetBytes,0,targetBytes.Length)];//char数组到targt编码字符串targetEncoding.GetChars(targetBytes,0,targetBytes.Length,targetChars,0);string targetString=新字符串(targetChars);return targetString;}私有字符串meCabParse(字符串jpnText){//将字符串中的文本从UTF-8转换为EUC-JPjpnText=convertEncoding(jpnText,65001200932);IntPtr mecab=mecab_new2(");string parsedText=mecab_sparse_tostr(mecab,jpnText);//annd转换回UTF-8parsedText=convertEncoding(parsedText209326501);mecab_destroy(mecab);}
建议/嘲讽?
我偶然发现这个线程正在寻找同样的方法。我使用您的代码作为起点,并使用这篇博客文章来了解如何封送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;
}
}