茶番(少しの間お遊びにおつきあい下さい)
4月26日金曜日の会社の夕方休憩時間中,いつもの通りZennとかQiitaのJulia情報を探していたところ, ふと一つの記事が目についた。
その書き出しはこんな感じだった。
「Julia テキストファイル 読み込み」でググってもパッとする記事が引っかからないので ...
え゛っ
同じキーワードでググって,確かにreadline(s)
とか使っているものが多いけどそこそこ
ちゃんとしてるのが引っかかるじゃんとか思って…
で記事を読んで…
え゛っ
これがこの著者の「パッとする記事」なのか?
そこで私はふと考える。
これは日本のJuliaユーザーに対する侮辱だ。いや中小企業でパッとしない立場の 数学者でもないプログラマーでもない,なんちゃって一人研究部署のJuliaユーザーに対する 挑戦だ。
私は祝一平氏でもないしすごぶる甘等でもないので,誰の挑戦でも受ける訳ではないし, おごられるアップルパイも全ては食べられないが,この挑戦は受けるべきではないか?
挑戦を受けるためにはまず調査だ。「彼を知り己を知れば百戦殆からず」とは誰の言葉だったか。
家に帰ってJuliaユーザーご用達「二冊の鈍器」実践Julia入門と Juliaプログラミング大全の中身をパラパラと開いてみる。 何と二冊合わせても「大全」の13.2ストリームぐらいしか言及がない。
ふむ
認めよう。確かに情報は少ない。
しかし,この記事を「パッとする記事」だとすると世界に対して日本のJuliaユーザーレベルに疑いをもたれてしまう。
それなら,低辺のJuliaユーザーであるこの私が「パッとする記事」を書くことで日本のJuliaユーザーの格は 相対的に飛躍的に上昇するだろう。
ならば書くしかない。この私が。
テキストファイル処理
だんだん飽きてきたので,この辺で普通の口調に戻して進めたいと思います。
まず,Juliaのopen
関数の戻り値は次の通りIOStream
なので,変数はfile
よりio
の方が適切です。
julia> io = open("mozc_julia_latex_dict.txt", "r") IOStream(<file mozc_julia_latex_dict.txt>)
元記事はPythonの影響かとも思ったのですが,
>>> file = open('mozc_julia_latex_dict.txt', 'r') >>> type(file) <class '_io.TextIOWrapper'>
とIOのラッパーだったりするので,確実なところだとC言語の影響でしょうか?
で,ここでテキストファイルの読み込み方は大きく三種類。ベタ,原理主義,最小限です。
ベタな方法は次の通り。
io = open("mozc_julia_latex_dict.txt", "r") text = read(io, String) close(io) println(text)
「ベタ」というのは close忘れがあること,処理中の変数が全部外に流れるので 処理中変数の海にさらされることが多いためです。
また,クローズしたio
が中ぶらりんになるのも今一つです。
ただ,Windows OSではファイルclose処理が遅く「あえて」全体の処理が終わるまでクローズしない
という技等に使えます。
なお, zipfile.readerで開いたファイルがclose出来ない 等での回答でもあるように,Windowsではclose忘れが致命的になることが多いので, ちゃんとしたい時は次の「原理主義」を使う方がいいでしょう。
次は原理主義です。
text = open("mozc_julia_latex_dict.txt", "r") do io read(io, String) end println(text)
私が「原理主義」と呼ぶのは「close忘れがない」ためです。
また,do節の中で複雑な処理をして最終行にtext
に入れる値を置けば
応用も効きやすいので基本はこれを使うべきです。
ただ,ネットの情報ではdo節の最終行を返り値として代入できることを知らないのか
println
で内容を表示している例が多いですが,基本は上のような形で使うべきです。
べき,べき,べき。だから「原理主義」。
次は「最小限」です。
text = read("mozc_julia_latex_dict.txt", String) println(text)
元々,Julia言語を使っているのは「自分が書くコードを最小にできそう」「自分が書くコードを少なくするためだったら何でもする」という理由からなので,私は断然「最小限」を選びます。
第1引数が関数の関数(余談)
余談にはなるのですが, text = open("in.txt", "r") do io ...
のような書き方ができるのは,
open(f:Function, arg...; kwargs...)
のように第1引数に関数を取れる関数がある時に記述できます。
ですので,
text = open(io -> read(io, String), "mozc_julia_latex_dict.txt", "r")
も「原理主義」のソースと同じ意味になります。
過去の日記の例を解説
実はテキスト処理についてはPlots.jlのGRバックエンド用フォントパッチ(Linux用)にさらっと使用例があります。
といっても元がテキストファイルではなく,コマンドの実行結果のテキスト情報を使っている違いがあります。 該当部分は次の通りです。
function gr_custom_fontlist_linux() コマンド出力 = pipeline(`fc-list`, `egrep "[.](ttf|ttc|otf)"`,`cut -d : -f 1`) 読込(x) = read(x, String) 終端改行削除(x) = chomp(x) 行分割(x) = split(x, "\n") ファイル名抽出(x) = basename(x) fnames = コマンド出力 |> 読込 |> 終端改行削除 |> 行分割 .|> ファイル名抽出 Dict([(chopsuffix(f, r"[.](ttf|ttc|otf)") , f) for f in fnames]) end
コマンド出力
のところは,fc-list
のテキスト出力の各行を :
で区切って1列目を選択して出力しています。
ですので次の読込
で読み込む文字列と同じになります。
読込
のところの文字列は次のような感じです。
""" /usr/share/fonts/truetype/lato/Lato-Medium.ttf /usr/share/fonts/truetype/noto/NotoSansTelugu-CondensedThin.ttf /usr/share/fonts/truetype/msttcorefonts/comicbd.ttf /usr/share/fonts/truetype/noto/NotoSerifHebrew-CondensedLight.ttf /usr/share/fonts/truetype/noto/NotoSans-SemiCondensedExtraLightItalic.ttf /usr/share/fonts/truetype/noto/NotoSansGurmukhi-ExtraCondensedMedium.ttf /usr/share/fonts/truetype/noto/NotoSerif-ExtraCondensedThinItalic.ttf /usr/share/fonts/truetype/noto/NotoSerifKhmer-Medium.ttf /usr/share/fonts/opentype/inter/InterDisplay-MediumItalic.otf /usr/share/fonts/truetype/noto/NotoSansEthiopic-ExtraLight.ttf /usr/share/fonts/truetype/noto/NotoSansArabic-CondensedThin.ttf """
行分割
のところで次のようなパス文字列配列に変換します。
["/usr/share/fonts/truetype/lato/Lato-Medium.ttf", "/usr/share/fonts/truetype/noto/NotoSansTelugu-CondensedThin.ttf", "/usr/share/fonts/truetype/msttcorefonts/comicbd.ttf", "/usr/share/fonts/truetype/noto/NotoSerifHebrew-CondensedLight.ttf", "/usr/share/fonts/truetype/noto/NotoSans-SemiCondensedExtraLightItalic.ttf", "/usr/share/fonts/truetype/noto/NotoSansGurmukhi-ExtraCondensedMedium.ttf", "/usr/share/fonts/truetype/noto/NotoSerif-ExtraCondensedThinItalic.ttf", "/usr/share/fonts/truetype/noto/NotoSerifKhmer-Medium.ttf", "/usr/share/fonts/opentype/inter/InterDisplay-MediumItalic.otf", "/usr/share/fonts/truetype/noto/NotoSansEthiopic-ExtraLight.ttf", "/usr/share/fonts/truetype/noto/NotoSansArabic-CondensedThin.ttf", ... ]
ファイル名抽出
のところでパス文字配列のファイル名文字列部分だけ抽出します。
["Lato-Medium.ttf", "NotoSansTelugu-CondensedThin.ttf", "comicbd.ttf", "NotoSerifHebrew-CondensedLight.ttf", "NotoSans-SemiCondensedExtraLightItalic.ttf", "NotoSansGurmukhi-ExtraCondensedMedium.ttf", "NotoSerif-ExtraCondensedThinItalic.ttf", "NotoSerifKhmer-Medium.ttf", "InterDisplay-MediumItalic.otf", "NotoSansEthiopic-ExtraLight.ttf", "NotoSansArabic-CondensedThin.ttf", ... ]
といった感じで処理を進めています。
限界...
とまぁこれぐらいが今日私が書ける限界になります。 最後までボケにつき合っていただいてありがとうございました。