LoginSignup
4
2

More than 3 years have passed since last update.

NKFtool : Julia プログラム内から漢字コードを変換する

Last updated at Posted at 2020-12-16

Julia Advent Calendar 2020,16日目です.

Julia で,漢字コード変換を行うパッケージ NKFtool を紹介します.

Julia は Unicode が大好き

Julia は Unicode が大好きです.変数名,関数名,演算子を,Unicode文字で表せます.(以前紹介記事を書きました → UTF-8 表記の演算子たち).

Julia の文字・文字列は、UTF-8 符号です. 可変長の UTF-8 を,Julia はしなやかに扱います.
例えば,eachindex(s) は,文字列 s に入っている各文字の添字(何バイト目か)を順番に取り出すイテレータです. 以下の例では,絵文字が 4 バイト,漢字が 3 バイト,半角文字は 1 バイトで表されていることが分かります.(絵文字 🍣 をJuliaの REPLで入力するには \:sushi: と入力してからTABキーで変換します).

julia> collect(eachindex("s🍣寿ss"))
5-element Array{Int64,1}:
  1
  2
  6
  9
 10

漢字コードの話

Unicode が使われる以前から,複数の漢字コードが存在しています.
主な漢字コードは,JISコード,日本語EUC (Extended Unix Code),Shift_JIS の三つです. 日頃 Windows 上で Microsoft Office を使う人は, Shift_JIS 文字(の拡張)を使っているはずです. 各種測定器が吐き出すファイルも Shift_JIS で書かれるものが多いです.

さて,UTF-8 以外で符号化されたファイルをJuliaで扱うには,事前に UTF-8 に変換したファイルを用意しておけばよいのですが、手間ですし,ファイルが増えてしまいます. 今回紹介する NKFtool を使えば、必要なときに Julia プログラム中からコード変換して読めるので、この悩みを解消できます.

nkf の紹介

nkf (Network Kanji Filter)は,漢字コード変換のためのコマンドライン・ツールです.

多くのパッケージマネージャから nkfをインストールできます.例えば,Mac の Homebrew からインストールするには

% brew install nkf

% nkf --version
Network Kanji Filter Version 2.1.5 (2018-12-15) 
Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa).
Copyright (C) 1996-2018, The nkf Project.

nkfは, Unicode や the Internet が広く普及する前から存在する由緒あるツールです)

文字コード変換の標準的なツールである iconv と比較して nkf は,以下の点で便利です.

  • 入力コードを自動で推定するので,指定しなくてよい(ただし、推定が失敗する場合もある)
  • 改行記号を変換できる (CR, LF, CR+LF)
  • 独自拡張された漢字コード(の一部)も取り扱うことができる

NKFtool の導入と起動

NKFtool パッケージは,Julia 内から nkf を呼ぶためのパッケージです.Juliaのパッケージマネージャからインストールできます.nkf は予め入れておいてください.

julia> # ] キーを押してパッケージモードに入る

pkg> add NKFtool

julia> # CTRL + C で REPL に戻る

NKFtool.nkf_version() は,nkf --version の出力を文字列として返します.

julia> nkf_version() |> println
Network Kanji Filter Version 2.1.5 (2018-12-15) 
Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa).
Copyright (C) 1996-2018, The nkf Project.

NKFtool.nkf_help() は,nkf --help の出力を文字列として返します. nkf のオプション確認に便利です.

julia> nkf_help() |> println
Usage:  nkf -[flags] [--] [in file] .. [out file for -O flag]
 j/s/e/w  Specify output encoding ISO-2022-JP, Shift_JIS, EUC-JP
          UTF options is -w[8[0],{16,32}[{B,L}[0]]]
 J/S/E/W  Specify input encoding ISO-2022-JP, Shift_JIS, EUC-JP
          UTF option is -W[8,[16,32][B,L]]
# 以下省略

漢字コードを推定する

NKFtool.nkf_guess(s) は,漢字コードを推定するコマンド nkf -g の出力を文字列として返します. 入力 s には,文字列またはストリームを指定します.

julia> nkf_guess("おはよう")
"UTF-8"

julia> nkf_guess(IOBuffer(raw"おはよう"))
"UTF-8"

漢字コードを変換する

NKFtool.nkf_convert(s, options) は,options に従い漢字コードを変換した文字列を返します. 入力 s には,文字列またはストリームを指定します. optionsnkf コマンドにそのまま渡されます (nkf --help で表示されるオプションの全てを指定できるわけではありません. 特に、入力ファイルを指定してしまうと、そこから文字列を読み込んでしまうでしょう).

出力漢字コードを指定する主なオプションは,以下の通りです.(小文字で指定します)

  • -j : JIS漢字コード,
  • -e : 日本語EUCコード,
  • -s : SHIFT_JIS コード
  • -w または -w0 : UTF-8

options は省略可能です。既定値は -w -m0 (出力コード UTF-8, no MIME encoding) です.

文字列を,色々な漢字コードに変換してみます. nkf_guess() を用いて,漢字コードが正しく推定されることを確かめましょう.

julia> nkf_convert( raw"おはよう", "-j") |> nkf_guess
"ISO-2022-JP"

julia> nkf_convert( raw"おはよう", "-e") |> nkf_guess
"EUC-JP"

julia> nkf_convert( raw"おはよう", "-s") |> nkf_guess
"Shift_JIS"

julia> nkf_convert( raw"おはよう", "-w") |> nkf_guess
"UTF-8"

julia> nkf_convert( raw"おはよう") |> nkf_guess
"UTF-8"

漢字コードを変えてファイルに書き込む

漢字コードを変えてファイルに書き込むには,nkf_convert(s, options) の結果を,出力ストリームに渡せばよいでしょう.

以下の例では Shift_JIS コードのファイルを作りました.

julia> open("morning_sjis.txt","w") do f
          print(f, nkf_convert(raw"おはよう\n", "-s"))
          print(f, nkf_convert(raw"おはよう\n", "-s"))
       end

julia> open("morning_sjis.txt") do f
         nkf_guess(f)
       end
"Shift_JIS"

julia> # 最初の1行で,コードを判定する
       readline("morning_sjis.txt") |> nkf_guess
"Shift_JIS"

ファイルから読み込む

色々な漢字コードで書かれたファイルから読み込むには,入力ファイルのストリーム fnkf_convert(f, options) に渡せばよいでしょう.

Julia文字列 として読み込む場合には options を省略してもよいです. (options の既定が -w -m0 だから)

julia> morning_utf=open("morning_sjis.txt") do f
          nkf_convert(f)
       end
"おはよう\\nおはよう\\n"

入力コードは誤判定がありうるので,事前に分かっているなら指定するとよいでしょう.
入力コードを指定する主なオプションは,以下の通りです.(各々の出力コード指定を大文字にした文字です)

  • -J : JIS漢字コード
  • -E : 日本語EUCコード
  • -S : SHIFT_JIS コード
julia> morning_utf=open("morning_sjis.txt") do f
          nkf_convert(f, "-S" )  # Shift_JIS コードを読む
       end
"おはよう\\nおはよう\\n"

Windows(の一部?)は,独自拡張した Shift_JIS コードを使用します(こちらの記事などを参照 → 本当は怖くないCP932nkfでCP932←→UTF-8の変換をする ). 例えば,CP932コードで書かれたテキスト・ファイルを読み込むなら --cp932 オプションを指定しましょう (--cp932 は, nkf --help には表示されない隠しオプションです).

julia> open("morning_cp932.txt","w") do f
          print(f, nkf_convert(raw"おはよう~\n", "--oc=cp932"))  # CP932 へ変換
       end

julia> open("morning_cp932.txt") do f
         nkf_guess(f)
       end
       # Shift_JIS として判定される
"Shift_JIS" 

julia> open("morning_cp932.txt") do f
          nkf_convert(f, "--cp932" )
       end
"おはよう~\\n"

Shift_JIS で書かれた CSV ファイルを読んで DataFrame を作る

応用として, Shift_JIS で書かれた CSV ファイルから, DataFrame を作ってみましょう。
私の用いているデータロガーは,次のような CSV ファイルを吐き出します.
(Shift_JIS で表されています)

AUTO0001.csv
"ファイル名","AUTO0001.CSV","V 1.11"
"タイトルコメント",""
"トリガ時刻","20-03-25 10:45:00"
"CH","Mode","Range","Comment","Scaling","Ratio","Offset"
"CH-1","電圧","100V","","OFF","-","-"
"CH-2","電圧","100V","","OFF","-","-"
"CH-3","熱電対","2000℃","","OFF","-","-"
"CH-4","熱電対","2000℃","","OFF","-","-"
"Time","CH-1[V]","CH-2[V]","CH-3[℃]","CH-4[℃]","Event",
 0.000000000E+00, 1.00000E-02, 1.50000E-02, 1.96000E+01, 1.94000E+01, 0,
 1.000000000E+01, 1.50000E-02, 1.00000E-02, 1.96000E+01, 1.93000E+01, 0,
 以下省略

これから DataFrame を作るには、以下の手順を踏みます.
まず NKFtool_convert() で UTF-8文字列に変換します. これを IOBuffer() に入れるとよいでしょう. データのヘッダ行は "Time" で始まる行として求められます. CSV.read(..., DataFrame) を呼ぶと DataFrame に変換できます.

using NKFtool
using CSV, DataFrames

# ヘッダー行を求める
function get_headerlineno(input_io)
   header_lineno=0
   lineno=0
   while true
      text=readline(input_io)
      isempty(text) && break
      lineno += 1
      # @show lineno, text
      if startswith(text,"\"Time\"")
         header_lineno=lineno
         break
      end
   end
   header_lineno
end

# CSV を読んで DataFrames を作る
function read_CSV(inout_csv_path)
   input_csv_texts = open(inout_csv_path) do f
      nkf_convert(f)
   end
   header_lineno=get_headerlineno(IOBuffer(input_csv_texts))
   CSV.read(IOBuffer(input_csv_texts), header=header_lineno, DataFrame)
end

実行してみましょう. 期待したとおりに DataFrame を作成できました (MacOSXターミナル上で起動した Julia REPLでは [℃][@@] に化けてしまいましたが、Visual Studio Code 内の Terminal で起動した Julia REPL では化けずに表示できました).

julia> read_CSV("~/AUTO0001.CSV") 
4×7 DataFrame
 Row  Time     CH-1[V]  CH-2[V]  CH-3[]  CH-4[]  Event  Column7 
      Float64  Float64  Float64  Float64   Float64   Int64  Missing 
─────┼───────────────────────────────────────────────────────────────
   1      0.0    0.01     0.015      19.6      19.4      0  missing 
   2     10.0    0.015    0.01       19.6      19.3      0  missing 
   3     20.0    0.015    0.01       19.5      19.4      0  missing 
   4     30.0    0.02     0.01       19.5      19.4      0  missing 
 以下省略

終わりに

以上、Juliaプログラム中で、漢字コードを変換できる NKFtool を紹介しました. CSV を経由して DataFrame を作れば、データ操作が早く楽になるはずです. どんどん活用しましょう.

また、同パッケージのソースは、Julia内でコマンドライン・ツールを呼ぶ例として参考になります。 別のツールを呼び出すパッケージを作る際に眺めてみるとよいでしょう。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2