第12回:テキストファイルの入出力
▶ テキストファイルの作成・書き込み
この節では,テキストファイルを作成し, テキストを書き込む方法を説明する. 一般のテキストファイルの拡張子は,txt である.
テキストファイルを作成するには,関数 open と close を組で用いる.
関数 open( fn, "w") は, ファイル名 fn のファイルを作成し, テキストを書き込む準備を行う. ファイル fn は,存在していてもよい.その場合は,元に書き込まれた内容は廃棄される.ファイルが作成できない場合には例外が発生する.
関数 open は,ファイル記述子 f を返す. 関数 print(f, s) は,ファイル記述子 f で指定されたファイルに文字列 s を書き込む. 関数 println(f, s) は,ファイル記述子 f で指定されたファイルに文字列 s を書き込んだ後に開業する.
書き込みが終わったら,関数 close(f) を呼び出し,書き込みを終了する.
f = open("hello1.txt", "w")
print(f, "Hello")
println(f, " again.")
close(f)上のプログラムを実行したら,Windows のエクスプローラを用いて,ファイル hello1.txt が作成されることを確かめよ. Windowsの「メモ帳」アプリなどを用いて hello1.txt を開き,その通りのテキストが書き込まれていることを観察・確認せよ. (※ MacOSの場合は,「ファインダー」アプリと,「テキスト・エディット」アプリに読み替えよ)
上と同じ処理は,do...end 構文を用いて書くこともできる. end が終わると関数 close(f) が暗黙的に呼ばれる.
open("hello1.txt", "w") do f
print(f, "Hello")
println(f, " again.")
end▶ 書式付き文字列と出力
書式を指定して,値を文字列に変換する場合には @sprintf() マクロを用いる. また,書式を指定して値を印字するには @printf() マクロを用いる. @sprintf,@printf はどちらも, Printf パッケージに定義されている. using Printf で,このパッケージを読み込んでから用いる.
マクロ @sprintf(fmt,x) は, x を 書式 fmt に従って文字列にする. マクロ @printf(fmt, x) は,その文字列を印字する. 書式文字列 fmt は, C言語の printf 関数などで用いられる書式と,ほぼ同じである.
なお,Jupyter notebookでは,結果が右寄せされて表示されない場合がある.
書式文字列 %i は,整数を印字する.
iの前に整数(フィールドサイズ)を付けると,その整数の幅で右寄せされて印字される.指定されたフィールドサイズで収まらない場合には,幅を増やして印字される.- フィールドサイズを
0で始めると,空白が0で埋められる. - フィールドサイズの前に
+を付けると,非負の数の前に+符号がつく.
julia> using Printfjulia> @printf("%5i\n", -41)-41julia> @printf("%05i\n", 413)00413julia> @printf("%+5i\n", 413)+413julia> @printf("%+5i\n", -413)-413julia> @printf("%+05i\n", -413)-0413julia> @printf("%+5i\n", -41131)-41131
書式文字列 %f は,小数を印字する.
fの前に整数(フィールドサイズ)を付けると,その整数の幅で右寄せされて印字される.指定されたフィールドサイズで収まらない場合には,幅を増やして印字される.- フォールドサイズに続けて,ピリオド
.と整数を付けると,小数点以下の桁数を指定する.指定された小数点以下桁数で表されない場合には,丸められる. - フィールドサイズを
0で始めると,頭の空白が0で埋められる. - フィールドサイズの前に
+を付けると,非負の数の前に+符号がつく. InfとNaNは,その通り印字される.
julia> @printf("%8.3f\n", -2e-2)-0.020julia> @printf("%08.0f\n", -0.252)-0000000julia> @printf("%8.1f\n", -0.252)-0.3julia> @printf("%08.2f\n", -0.252)-0000.25julia> @printf("%8.3f\n", -0.252)-0.252
書式文字列 %e は,指数形式で印字する.
eの前に整数(フィールドサイズ)を付けると,その整数の幅で右寄せされて印字される.フィールドサイズで収まらない場合には,幅を増やして印字される.- フォールドサイズに続けて,ピリオド
.と整数を付けると,小数点以下の桁数を指定する.指定された小数点以下桁数で表されない場合には,丸められる. - フィールドサイズを
0で始めると,頭の空白が0で埋められる. - フィールドサイズの前に
+を付けると,非負の数の前に+符号がつく. InfとNaNは,その通り印字される.
julia> @printf("%11.5e\n", -0.0078125)-7.81250e-03julia> @printf("%12.4e\n", -0.0078125)-7.8125e-03julia> @printf("%13.3e\n", -0.0078125)-7.812e-03julia> @printf("%13.2e\n", -0.0078125)-7.81e-03julia> @printf("%13.1e\n", -0.0078125)-7.8e-03
書式文字列 %s は,文字列形式で印字する.
sの前に整数(フィールドサイズ)を付けると,その整数の幅で右寄せされて印字される.フィールドサイズで収まらない場合には,幅を増やして印字される.
julia> @printf("%8s\n", "Hello")Hellojulia> @printf("%8s\n", "Hello world")Hello world
- 書式は復数使用してもよい.書式があるのに,印字すべき値がないと例外が発生する.
- 書式を指定しない文字は,そのまま印字される.
\nは改行文字を表す.\tはタブ(TAB)文字を表す.
julia> @printf("%.1f %15.7e\n", 0.025, -0.0078125)0.0 -7.8125000e-03julia> @printf("x=%.1f y=%15.7e\n", 0.025, -0.0078125) # 引数が足りない例x=0.0 y= -7.8125000e-03julia> @printf("%.1f %15.7e\n", 0.025)ERROR: ArgumentError: Number of format specifiers and number of provided args differ: 2 != 1
▶ 書式を指定して,テキストファイルに書き込む.
正規乱数 10 個からなるCSVファイルを書き出そう. 関数 @printf の第一引数に,ファイル記述子 f を入れると,f で示されたファイルに印字される.
using Printf
open("test1.txt", "w") do f
for i = 1:10
@printf(f, "%15.7f\n", randn())
end
end上のプログラムが正しく動作したら,test1.txt が作成されるはずである. このファイルを開き,数字が指定された書式で書き込まれたことを観察・確認せよ. さらに,「Excel」アプリを起動し,このファイルを1列のデータとして読み込んでみよ.
▶ CSVファイルへの書き込み
カンマ , で区切られた値が並ぶ行から構成されるテキストファイルを CSV(Comma Separated Value) ファイルという. 表計算ソフトウエアとのデータの輸入輸出によく用いられる. 拡張子は csv である.
関数 @printf を用いて,整数と浮動小数点数をカンマで区切った行を書き出そう.
なお,CSVファイルの1行目に,カンマ , で区切られた文字列を,各列の表題として書くことが多い.
using Printf
open("test2.csv", "w") do f
println(f, "i,x")
for i = 1:10
@printf(f, "%i,%15.7f\n", i, randn())
end
end上のプログラムが正しく動作したら,test2.csv が作成されるはずである. このファイルを開き,プログラムの指示通り書き込まれたか観察・確認せよ. さらに,「Excel」アプリを起動し,2列のデータとして読み込んでみよ.
▶ テキストファイルからの読み込み
▶ テキストファイルからの行単位の読み込み
関数 open( fn ) は,ファイル名 fn のファイルをテキストとして,読み込む準備を行う. ファイル fn が読み込めない場合には例外が発生する.
テキストファイルを読み込むためにも,関数 open と close を組で用いる.
以下のプログラムは,テキストファイルから,1行ずつ読み込み,それを印字する.
関数 eachline(f) は,ファイル記述子 f からテキストを読み込み,行に分割する.このとき,行末の改行文字は取り除かれる.
f = open("hello1.txt")
for line in eachline(f)
print(line)
end
close(f)Hello again.書き込みの場合と同様に,do...end 構文を用いて書くこともできる. end が終わると関数 close(f) が暗黙的に呼ばれる.
open("hello1.txt") do f
for line in eachline(f)
print(line)
end
endHello again.▶ 文字列から数に変換する
文字列を数に変換するには,関数 parse(t, s)を用いる. 第一引数には変換先の型を,第二引数には,変換したい文字列を書く.文字列の前後の空白は無視される.
julia> parse(Float64, " 12.3")12.3julia> parse(Float64, " 12.3e-2 ")0.123julia> parse(Int64, " 123 ") # 変換できない例123julia> parse(Int64, " 12.3 ")ERROR: ArgumentError: invalid base 10 digit '.' in " 12.3 "
上のプログラムで作成したファイル test1.txt から1行ずつ読み込み,浮動小数点数に変換して印字してみよう.
open("test1.txt") do f
for line in eachline(f)
x = parse(Float64, line)
@printf("%15.7f\n", x)
end
end -0.3844436
0.6654147
2.0245069
-0.0008339
0.7039418
-0.7263235
0.0881307
-0.5442422
-0.2035987
-1.1870459▶ 文字列を分割する
関数 split(s, c) は,文字列を分割する. 第一引数の文字列 s を,第二引数の文字列のどれか一つの文字が出現したら分割する.結果として,文字列を要素とする配列が返される.
英文テキストを,空白で区切る.
julia> split("one cup of brown suger", " ")5-element Vector{SubString{String}}: "one" "cup" "of" "brown" "suger"
行をカンマで区切って,それぞれ整数と浮動小数点数に変換する.
julia> line = " 15 , 0.2401863"" 15 , 0.2401863"julia> s = split(line, ",")2-element Vector{SubString{String}}: " 15 " " 0.2401863"julia> parse(Int64, s[1])15julia> parse(Float64, s[2])0.2401863
上のプログラムで作成した test2.csv を読み込み,各行を整数と浮動小数点数に変換し,印字する. ただし,1行目は読み飛ばす.
using Printf
open("test2.csv") do f
i = 0
for line in eachline(f)
i += 1
i == 1 && continue
s = split(line, ",")
x = parse(Int64, s[1])
y = parse(Float64, s[2])
@printf("%5i %15.7f\n", x, y)
end
end 1 0.2658296
2 -1.2140886
3 0.3546363
4 -0.9952465
5 0.4713023
6 -0.5732707
7 -0.9260864
8 -1.0978113
9 -2.5159664
10 -1.5457950▶ 配列に要素を加える
関数 push!(a,x) は,配列 a に,値 x を付け加える.配列 a は書き換えられる.
julia> # Int64 を要素とする配列 xs = [1, 2]2-element Vector{Int64}: 1 2julia> push!(xs, 3)3-element Vector{Int64}: 1 2 3julia> xs3-element Vector{Int64}: 1 2 3julia> push!(xs, 4)4-element Vector{Int64}: 1 2 3 4julia> xs4-element Vector{Int64}: 1 2 3 4
要素がない配列を作るには 関数 zeros(t, 0) を使えばよい. 第一引数 t は,作成する配列の要素である.
以下では,Float64 型の配列(要素数 $0$)を最初に作成した.
julia> xs = zeros(Float64, 0)Float64[]julia> push!(xs, 1.0)1-element Vector{Float64}: 1.0julia> xs1-element Vector{Float64}: 1.0julia> push!(xs, 2.0)2-element Vector{Float64}: 1.0 2.0julia> xs2-element Vector{Float64}: 1.0 2.0
▶ CSVファイルから配列を作る
以上を組合せて,CSVファイルを読み込み,値を配列としてまとめることができる.
using Printf
xs = zeros(Int64, 0)
ys = zeros(Float64, 0)
open("test2.csv") do f
i = 0
for line in eachline(f)
i += 1
i == 1 && continue
s = split(line, ",")
x = parse(Int64, s[1])
push!(xs, x)
y = parse(Float64, s[2])
push!(ys, y)
end
end
@show xs
@show ys10-element Vector{Float64}:
0.2658296
-1.2140886
0.3546363
-0.9952465
0.4713023
-0.5732707
-0.9260864
-1.0978113
-2.5159664
-1.545795続けて,データを描くと,
using Plots
scatter(ys, shape=:circle)
▶ CSVパッケージ
CSV パッケージを用いると,CSVファイルを容易に扱うことができる.
CSV パッケージを設置(インストール)していない場合は,次のように設置する.
import Pkg;
Pkg.add("CSV") Resolving package versions...
No Changes to `~/work/memoProgClass2024w.jl/memoProgClass2024w.jl/docs/Project.toml`
No Changes to `~/work/memoProgClass2024w.jl/memoProgClass2024w.jl/docs/Manifest.toml`CSV パッケージに定義されている関数 CSV.read(fn, DataFrame) を用いると,CSVファイル fn を読み込むことができる. 結果として,拡張された配列( DataFrame 型)が返される.
# CSV
using CSV, DataFrames
df = CSV.read("test2.csv", DataFrame)
# 1番目のデータ配列
@show df[:,1]
# 2番目のデータ配列
@show df[:,2]
#
using Plots
scatter(df[:,2], shape=:circle)
データを描いた結果は,上と同じである.
★ 今回のまとめ
- 文字列の扱い
- ,出力
- 文字列の分割
- 文字列から数への変換
- 配列に要素を加える
- テキストファイル
- 書き込み
- 読み込み
- CSVファイル