YAS's VB.NET Tips
 
VB.NET Tips
VB.NET Tips >> 記事詳細

2018/06/24

MS-IMEでモノルビを取得する

| by:YAS
 MS-IMEでモノルビを取得します。Text Services Framework(TSF)を利用して,文全体の読み仮名や,一つ一つの文字に対しての読み仮名を取得することができます。

※下のコードは今ひとつ不安定です。APIの定義が間違っているのかもしれません。









下のコードをフォームのコードにコピー・貼り付けをすれば動作します。
Option Explicit On
Option Strict On

Imports System.Runtime.InteropServices

Public Class Form1

    
Private WithEvents TextBox1 As New TextBox With {.Multiline = True, .Dock = DockStyle.Fill}
    
Private MsIme As Type = Type.GetTypeFromProgID("MSIME.Japan")
    
Private Language As IFELanguage = DirectCast(Activator.CreateInstance(MsIme), IFELanguage)

    
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        
Me.Controls.Add(TextBox1)
        Language.Open()
        
Dim KanjiText As String = "天気予報によると,明日は晴れになるでしょう。"
        
Dim List As List(Of kanjiRuby) = getMonoRuby(KanjiText)
        
For Each l In List
            
Me.TextBox1.Text &= l.kanji & "(" & l.ruby & ")" & vbCrLf
        
Next
        Language.Close()
        Marshal.FinalReleaseComObject(Language)
    
End Sub

    
Public Function getMonoRuby(kanjiSentence As StringAs List(Of kanjiRuby)
        
Dim resultPtr As IntPtr
        
Dim hr As Integer = Language.GetJMorphResult(FELANG_REQ.REV, FELANG_CMODE.MONORUBY, kanjiSentence.Length, kanjiSentence, 0, resultPtr)
        
Dim result As MORRSLT = DirectCast(Marshal.PtrToStructure(resultPtr, GetType(MORRSLT)), MORRSLT)
        
'MonoRubyPosをリストにコピーする
        
Dim length As Integer = kanjiSentence.Length
        
Dim kanjiRubyPosList = {New With {.kanji = "", .rubyPos = 0}}.ToList
        kanjiRubyPosList.Clear()
        
For i As Integer = 0 To length
            
Dim kanji As String = If(i < length, kanjiSentence.Substring(i, 1), "")
            
Dim rubyPos As Integer = CInt(Marshal.ReadInt16(result.paMonoRubyPos, i * 2))
            kanjiRubyPosList.Add(
New With {kanji, rubyPos})
        
Next
        
'熟字訓をまとめる
        
For i As Integer = length To 0 Step -1
            
If kanjiRubyPosList(i).rubyPos = -1 Then
                kanjiRubyPosList(i - 1).kanji &= kanjiRubyPosList(i).kanji
                kanjiRubyPosList.Remove(kanjiRubyPosList(i))
            
End If
        
Next
        
'モノルビをふる
        
Dim rubySentence As String = Marshal.PtrToStringUni(result.pwchOutput, CInt(result.cchOutput))
        
Dim kanjiRubyList As New List(Of kanjiRuby)
        
For i As Integer = 0 To kanjiRubyPosList.Count - 2
            
Dim kanji As String = kanjiRubyPosList(i).kanji
            
Dim rubyStartPos As Integer = kanjiRubyPosList(i).rubyPos
            
Dim rubyEndPos As Integer = kanjiRubyPosList(i + 1).rubyPos
            
Dim rubyLength As Integer = rubyEndPos - rubyStartPos
            
Dim ruby As String = rubySentence.Substring(rubyStartPos, rubyLength)
            kanjiRubyList.Add(
New kanjiRuby With {.kanji = kanji, .ruby = ruby})
        
Next
        
Return kanjiRubyList
    
End Function

    
Public Class kanjiRuby
        
Property kanji As String
        
Property ruby As String
    
End Class

End Class

'参考
'msime.h ダウンロード
'https://www.microsoft.com/en-us/download/details.aspx?id=9739
'IFELanguage::GetJMorphResult method
'https://msdn.microsoft.com/ja-jp/library/windows/desktop/hh851782(v=vs.85).aspx
'searchcode imelib /ImeLibSrc/WinApi/MsIme.cs 
'https://searchcode.com/codesearch/view/10960462/

Public NotInheritable Class Interface_ID
    
Public Const IID_IFECommon As String = "019F7151-E6DB-11d0-83C3-00C04FDDB82E"
    
Public Const IID_IFELanguage As String = "019F7152-E6DB-11d0-83C3-00C04FDDB82E"
    
Public Const IID_IFELanguage2 As String = "21164102-C24A-11d1-851A-00C04FCC6B14"
    
Public Const IID_IFEDictionary As String = "019F7153-E6DB-11d0-83C3-00C04FDDB82E"
End Class

<ComImport>
<Guid(Interface_ID.IID_IFELanguage)>
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Public Interface IFELanguage
    <PreserveSig>
    
Function Open() As Integer
    <PreserveSig>
    
Function Close() As Integer
    <PreserveSig>
    
Function GetJMorphResult(<[In]> dwRequest As FELANG_REQ,                                'The conversion request.
                             <[In]> dwCMode 
As FELANG_CMODE,                                'Specifies the conversion output characters and conversion options.
                             <[In]> cwchInput 
As Integer,                                   'The number of characters in pwchInput.
                             <[In], MarshalAs(UnmanagedType.LPWStr)> pwchInput 
As String,   'Input characters to be converted by the morphology engine. This must be a UNICODE string.
                             <[In]> 
ByRef pfCInfo As FELANG_CLMN,                           'The information for each column, where each pfCInfo[x] corresponds to pwchInput[x].
                             <Out> 
ByRef ppResult As IntPtr) As Integer                     'The address of a MORRSLT structure that receives the morphology result data.
    <PreserveSig>
    
Function GetConversionModeCaps(<Out> ByRef pdwCaps As UIntegerAs Integer
    <PreserveSig>
    
Function GetPhonetic(<[In]> [string] As String,
                         <[In]> start 
As Integer,
                         <[In]> length 
As Integer,
                         <Out> 
ByRef phonetic As StringAs Integer
    <PreserveSig>
    
Function GetConversion(<[In], MarshalAs(UnmanagedType.BStr)> [string] As String,
                           <[In]> start 
As Integer,
                           <[In]> length 
As Integer,
                           <Out> 
ByRef result As StringAs Integer
End Interface

Public Enum FELANG_REQ As UInteger
    CONV = &H10000
    RECONV = &H20000
    REV = &H30000
End Enum

Public Enum FELANG_CLMN As UInteger
    WBREAK = &H1
    NOWBREAK = &H2
    PBREAK = &H4
    NOPBREAK = &H8
    FIXR = &H10
    FIXD = &H20                     
'fix display of word
End Enum

Public Enum FELANG_CMODE As UInteger
    MONORUBY = &H2                  
'mono-ruby
    NOPRUNING = &H4                 
'no pruning
    KATAKANAOUT = &H8               
'katakana output
    HIRAGANAOUT = &H0               
'default output
    HALFWIDTHOUT = &H10             
'half-width output
    FULLWIDTHOUT = &H20             
'full-width output
    BOPOMOFO = &H40                 
'
    HANGUL = &H80                   

    PINYIN = &H100                  

    PRECONV = &H200                 
'do conversion as follows:
    RADICAL = &H400                 
'
    UNKNOWNREADING = &H800          
'
    MERGECAND = &H1000              
'merge display with same candidate
    ROMAN = &H2000                  
'
    BESTFIRST = &H4000              
'only make 1st best
    USENOREVWORDS = &H8000          
'use invalid revword on REV/RECONV.
    NONE = &H1000000                
'IME_SMODE_NONE
    PLAURALCLAUSE = &H2000000       
'IME_SMODE_PLAURALCLAUSE
    SINGLECONVERT = &H4000000       
'IME_SMODE_SINGLECONVERT
    AUTOMATIC = &H8000000           
'IME_SMODE_AUTOMATIC
    PHRASEPREDICT = &H10000000      
'IME_SMODE_PHRASEPREDICT
    CONVERSATION = &H20000000       
'IME_SMODE_CONVERSATION
    NAME = PHRASEPREDICT            
'Name mode (MSKKIME)
    NOINVISIBLECHAR = &H40000000    
'remove invisible chars (e.g. tone mark)
End Enum

<StructLayout(LayoutKind.Explicit, Size:=48, Pack:=1)>
Public Structure MORRSLT
    <FieldOffset(0)> 
Public dwSize As UInt32           'DWORD dwSize;          total size of this block.
    <FieldOffset(4)> 
Public pwchOutput As IntPtr       'WCHAR *pwchOutput;     conversion result string.
    <FieldOffset(8)> 
Public cchOutput As UInt16        'WORD  cchOutput;       lengh of result string.    
    <FieldOffset(10)> 
Public pwchRead As IntPtr        'union {WCHAR *pwchRead;WCHAR *pwchRead;} reading string
    <FieldOffset(14)> 
Public cchRead As UInt16         'union {WORD cchRead;WORD cchComp;} length of reading string.
    <FieldOffset(16)> 
Public pchInputPos As IntPtr     'WORD  *pchInputPos;    index array of reading to input character.
    <FieldOffset(20)> 
Public pchOutPutIdxWDD As IntPtr 'WORD  *pchOutputIdxWDD;index array of output character to WDD
    <FieldOffset(24)> 
Public pchReadIdxWDD As IntPtr   'union {WORD *pchReadIdxWDD;WORD  *pchCompIdxWDD;} index array of reading character to WDD
    <FieldOffset(28)> 
Public paMonoRubyPos As IntPtr   'WORD  *paMonoRubyPos;  array of position of monoruby
    <FieldOffset(32)> 
Public pWDD As IntPtr            'WDD   *pWDD;           pointer to array of WDD
    <FieldOffset(36)> 
Public cWDD As Int32             'INT   cWDD;            number of WDD
    <FieldOffset(40)> 
Public pPrivate As IntPtr        'VOID  *pPrivate;       pointer of private data area
    <FieldOffset(44)> 
Public BLKBuff As IntPtr         'WCHAR BLKBuff[];       area for stored above members.
End Structure

''64bitの定義
'<StructLayout(LayoutKind.Explicit, Size:=84, Pack:=1)>
'Public Structure MORRSLT
'    <FieldOffset(0)> Public dwSize As UInt32           'DWORD dwSize;          total size of this block.
'    <FieldOffset(4)> Public pwchOutput As IntPtr       'WCHAR *pwchOutput;     conversion result string.
'    <FieldOffset(12)> Public cchOutput As UInt16       'WORD  cchOutput;       lengh of result string.    
'    <FieldOffset(14)> Public pwchRead As IntPtr        'union {WCHAR *pwchRead;WCHAR *pwchRead;} reading string
'    <FieldOffset(22)> Public cchRead As UInt16         'union {WORD cchRead;WORD cchComp;} length of reading string.
'    <FieldOffset(24)> Public pchInputPos As IntPtr     'WORD  *pchInputPos;    index array of reading to input character.
'    <FieldOffset(32)> Public pchOutPutIdxWDD As IntPtr 'WORD  *pchOutputIdxWDD;index array of output character to WDD
'    <FieldOffset(40)> Public pchReadIdxWDD As IntPtr   'union {WORD *pchReadIdxWDD;WORD  *pchCompIdxWDD;} index array of reading character to WDD
'    <FieldOffset(48)> Public paMonoRubyPos As IntPtr   'WORD  *paMonoRubyPos;  array of position of monoruby
'    <FieldOffset(56)> Public pWDD As IntPtr            'WDD   *pWDD;           pointer to array of WDD
'    <FieldOffset(64)> Public cWDD As Int32             'INT   cWDD;            number of WDD
'    <FieldOffset(68)> Public pPrivate As IntPtr        'VOID  *pPrivate;       pointer of private data area
'    <FieldOffset(76)> Public BLKBuff As IntPtr         'WCHAR BLKBuff[];       area for stored above members.
'End Structure

19:12 | コメント(0)
メニュー