Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

PowerShellで法務省 戸籍統一文字情報のページからあるコードポイントの文字の情報を取得する

(In English: How to get information about a Japanese character from 戸籍統一文字情報 site (managed by The Ministry of Justice (Japan)) with PowerShell)

問題:

ある漢字に関する情報(読みや、子の名に使える文字か等)を調べたければ、法務省戸籍統一文字情報のページが利用できる。 ただしこのページではフォームからいちいちUnicodeのコードポイントなどを入力して検索する必要があり、複数の文字の情報を一括で取得するには向いていない。

対策:

PowerShellで、指定した文字の情報を取得するコマンドレットGet-KosekiMojiを作成した。 このコマンドレットを使ってGet-KosekiMoji -CodePoint "90CE"U+90CEは「郎」のコードポイント)のように実行すると、対応する文字の情報を戸籍統一文字情報のページから検索し、その結果を取得する。

  • 文字はUnicodeまたはシフトJISのコードポイントで指定する。デフォルトはUnicodeのコードポイントで、引数に-Charset "ShiftJIS"を指定するとシフトJISのコードポイントで検索する。
  • 今のところ、BMP面の文字でのみ動作確認を行っている。
  • 戻り値はPsCustomObject型で、取得する情報と格納先パラメータは以下の通り。
  • 戸籍統一文字情報のページに登録されていない文字(戸籍統一文字番号が付与されていない文字)に対しては$nullが返る。

注意事項:

このコマンドレットは、1回の呼び出しにつき、戸籍統一文字情報のページへ2回アクセスを行う。 スクリプト中で繰り返し使用する際は、戸籍統一文字情報のページに高い負荷がかからないよう、Start-Sleepなどを利用して、適切な間隔を開けて呼び出すこと。

2017/05/07追記:

当初はUnicodeのコードポイントのみ指定可能としていたが、シフトJISでも指定可能なようにオプションを追加した。 これは、シフトJISWindows-31Jマッピングが異なる文字(「¢」など)を検索する際、シフトJISマッピングである「U+00A2」で検索されるべきところ、PowerShellではUnicodeのコードポイントを求める際にWindows-31Jマッピングしか使用できず、「U+FFE0」で検索されてしまうのが避けられなかったため。

function Get-KosekiMoji {
  Param(
    [Parameter(ValueFromPipeline=$true,Mandatory=$true)]
    [string] $CodePoint,
    [string] $Charset = "Unicode"

  )
  begin {
    if ($PSVersionTable.PSEdition -eq "Core") {
      [System.Text.Encoding]::RegisterProvider([System.Text.CodePagesEncodingProvider]::Instance)
    }
    $SearchUri = 'http://kosekimoji.moj.go.jp/kosekimojidb/mjko/PeopleSearch/EXECUTE?ihid_clickedButtonName=iimg_Search&irdo_Code={0}&itxt_Code={1}&irdo_Jyoken=AND&itxt_Yomi1=&itxt_Yomi2=&itxt_Yomi3=&islc_Kakusu1=0&islc_Kakusu2=&islc_Jis=0&ihid_ScreenId=Search&ihid_Busyu1=&ihid_Busyu2=&ihid_Busyu3='
    $KskMjUri = 'http://kosekimoji.moj.go.jp/kosekimojidb/mjko/PeopleList/EXECUTE?ihid_clickedButtonName=iimag_Moji&ihid_SelectedKskMjBng={0}&ihid_SearchCount=0'
    $KskMjProperties = "KskMjBng", "On", "JoyoOn", "Kun", "JoyoKun", "Strokes", "JIS", "JIS2004", "Dummy1", "Unicode", "Dummy2", "UnicodeJIS2004", "Dummy3", "SJIS", "Dummy4", "SJIS2004", "KskMjKbn", "KskMjOyaKbn"
    $SavedProgressPreference = $ProgressPreference
    $ProgressPreference = "SilentlyContinue"
  }
  process {
    if ($Charset -eq "Unicode") {
      $CharsetNumber = 2
    } elseif ($Charset -eq "ShiftJIS") {
      $CharsetNumber = 4
    } else {
      $CharsetNumber = 2
    }
    $SearchRequest = (Invoke-WebRequest -Uri ($SearchUri -F $CharsetNumber, $CodePoint))
    $SearchHtml = [System.Text.Encoding]::GetEncoding(932).GetString($SearchRequest.RawContentStream.ToArray());
    if ($SearchHtml -match '/kosekimojidb/png\?kosekiMjBng=(?<KskMjBng>[0-9]+)&pngSizeKbn=1') {
      $KskMjBng = $Matches.KskMjBng
      $KskMjResponse = (Invoke-WebRequest -Uri ($KskMjUri -F $KskMjBng))
      $KskMjHtml = [System.Text.Encoding]::GetEncoding(932).GetString($KskMjResponse.RawContentStream.ToArray());
      $KskMjHtml -match '<td colspan="2" nowrap class="sec">(?<KskMjOyaKbn>.+?)</td>' > $null
      $KskMjOyaKbn = $Matches.KskMjOyaKbn
      ($KskMjHtml.Split("`r") | ForEach-Object { if ($_ -like '*class="normal"*') { if ($_ -match '<.+?>(.*?)</.+?>') { $Matches.1 } } }) -join "," | Set-Variable KskMjDataCsv
      $KskMjDataCsv + "," + $KskMjOyaKbn | ConvertFrom-Csv -Header $KskMjProperties | Set-Variable KskMjData
      $KskMjData.PSObject.Properties.Remove("Dummy1")
      $KskMjData.PSObject.Properties.Remove("Dummy2")
      $KskMjData.PSObject.Properties.Remove("Dummy3")
      $KskMjData.PSObject.Properties.Remove("Dummy4")
      $KskMjData
    }
  }
  end {
    $ProgressPreference = $SavedProgressPreference
  }
}