2011-06-16 1 views
2

J'essaie d'utiliser l'analyseur morphologique japonais MeCab dans un programme C# (Visual Studio 2010 Express, Windows 7), et quelque chose ne va pas avec l'encodage. Si mon entrée (collé dans une zone de texte) est la suivante:Essayant d'obtenir libmecab.dll (MeCab) pour travailler avec C#

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

Puis ma sortie (dans une autre zone de texte) ressemble à ceci:

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

Je suppose que c'est le texte dans un autre encodage se tromper pour le texte codé en UTF-8. Mais supposer que c'est EUC-JP et utiliser Encoding.Convert pour le transformer en UTF-8 ne change pas la sortie; en supposant que c'est Shift-JIS et faire la même chose donne un charabia différent. De plus, alors qu'il traite définitivement le texte - c'est ainsi que la sortie de MeCab est censée être formatée - il ne semble pas non plus interpréter l'entrée comme UTF-8. Si c'était le cas, il n'y aurait pas toutes ces lignes identiques dans la sortie commençant par des «composés» à un caractère, qu'il est clairement impossible d'identifier.

Je reçois encore un autre ensemble de charabia quand je lance la phrase à travers la ligne de commande de MeCab. Mais, encore une fois, c'est juste une rangée de simples points d'interrogation et de parenthèses qui descendent à gauche, donc ce n'est pas seulement le problème que la ligne de commande Windows ne supporte pas les polices avec des caractères japonais; encore une fois, il ne lit pas l'entrée en UTF-8. (Je l'ai fait installer MeCab en mode UTF-8.)

Les parties pertinentes du code ressembler à ceci:

 
[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; 
} 

(En termes de jongler avec des choses plausibles qui cherchent à voir si elles font une différence , J'ai essayé de passer "UnmanagedType.AnsiBStr" à "UnmanagedType.BStr", ce qui donne l'erreur "AccessViolationException n'a pas été gérée", et en ajoutant "CharSet = CharSet.Unicode" aux paramètres DllImport, qui ont transformé la sortie en juste "EOS ".)

Voici comment j'ai fait la conversion:

 
// 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); 
} 

Suggestions/railleries?

+0

Savez-vous ce que l'encodage de votre dictionnaire est? Essayez de lancer mecab -D et voyez quel jeu de caractères est utilisé. – buruzaemon

+0

Il est configuré pour utiliser le dictionnaire ipadic-utf8. – snarp

Répondre

2

Je suis tombé sur ce fil à la recherche d'un moyen de faire la même chose. J'ai utilisé votre code comme point de départ et this blog post pour déterminer comment marshaler les chaînes UTF8.

Le code suivant me donne une sortie correctement codé:

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

OUI! Ça marche! Merci beaucoup d'avoir posté votre solution. Je ne sais pas pourquoi je ne suis jamais tombé sur cette entrée de blog pendant que je cherchais sur Google. – snarp