一般解は
https://stackoverflow.com/questions/69385888/parse-multi-line-result-text-file-with-awk-bash-or-r
にあった。AWK スクリプトを平易に書き変えた。
★ 以下のような定式化された入力ファイル melting.txt
The MELTING results are :
Enthalpy : -181,100 cal/mol ( -756,998 J /mol)
Entropy : -467.3 cal/mol-K ( -1,953.31 J /mol-K)
Melting temperature : 75.13 degrees C.
The MELTING results are :
Enthalpy : -170,800 cal/mol ( -713,944 J /mol)
Entropy : -444 cal/mol-K ( -1,855.92 J /mol-K)
Melting temperature : 70.6 degrees C.
からデータを取り出し,R で
Enthalpy Entropy MeltingTemperature
1 -181100 -467.3 75.13
2 -170800 -444.0 70.60
のようなデータフレームを作る。
★ 用意する AWK スクリプト melting.awk
/Enthalpy/ || /Entropy/ { # "Enthalpy" または "Entropy" を含む行について
n = split($0, a, " ") # 空白でフィールドに区切る
gsub(",", "", a[3]) # a[3] が求めるデータである。数値区切りの「,」を消去する
printf "%g, ", a[3] # 書き出す
}
/Melting temperature/ { # "Melting temperature" を含む行について
n = split($0, a, " ") # 空白でフィールドに区切る
print a[4] # 求めるデータ a[4] を書き出す
}
★ R コンソールで以下を実行する。
CSV ファイルに結果を書き出す。
以下で |> を使っているが,tidyverse ではなく Base R のパイプである。
最初の文字列がコンソールで入力されるコマンドである。(脚注参照)
"awk -f melting.awk melting.txt" |>
pipe() |>
readLines() |>
write("results.csv")
後は,ありふれた処理。CSV ファイルをデータフレームに読み込むだけである。
df = read.csv("results.csv", header=FALSE,
col.names=c("Enthalpy", "Entropy", "MeltingTemperature"))
出来上がり。
Enthalpy Entropy MeltingTemperature
1 -181100 -467.3 75.13
2 -170800 -444.0 70.60
なお,入力ファイルがちゃんと同じフォーマットであることを仮定している。
その仮定ができない場合の処理を AWK スクリプトに含めるかどうかは,程度問題。
==========
脚注
以下の一行をコンソールで入力すれば
$ > awk -f melting.awk melting.txt
以下が表示される
-181100, -467.3, 75.13
-170800, -444, 70.6
結果をファイルに入れるには出力を results.csv へリダイレクトすればよい。
$ > awk -f melting.awk melting.txt > results.csv
=================
なお,R だけでやろうとすると以下のようにもなるだろうか。
txt = readLines("melting.txt")
df = NULL
x = NULL
for (i in 1:length(txt)) {
if (grepl("Enthalpy", txt[i]) || grepl("Entropy", txt[i])) {
target = sub(",", "", unlist(strsplit(txt[i], " "))[4])
x = append(x, target)
} else if (grepl("Melting temperature", txt[i])) {
x = append(x, unlist(strsplit(txt[i], " "))[5])
df = rbind(df, x)
x = NULL
}
}
df = as.data.frame(df, col.names=c("Enthalpy", "Entropy", "MeltingTemperature"))
print(df)
Julia でやろうとすると以下のようになる(書式に関して別の仮定を置く)
using DataFrames
txt = readlines("melting.txt")
x = Float64[]
for s in txt
pos = findfirst(r"[-+]?[0-9,]+\.?[0-9]*", s)
isnothing(pos) == false && append!(x, parse(Float64, replace(s[pos], "," => "")))
end
df = DataFrame(Matrix(reshape(x, 3, :)'), ["Enthalpy", "Entropy", "MeltingTemperature"])