Edited at

整数, 小数, 浮動小数点数の正規表現


概要

シェルを使って数値データファイルの整形を行っている際,正規表現で詰まったのでメモ代わりに.

整数(1,2,3,...)と小数(1.1,2.5,...)と浮動小数点数(1.0E+10, 1.6e-19, ...)が入り混じったファイルから数値を抜き出す正規表現.


正規表現

以下の様な正規表現で抜き出せた.

[+-]?[0-9]+[\.]?[0-9]*[eE]?[+-]?[0-9]*

実際にはこれをgrepなりegrepなりに突っ込んで抜き出す.

2016/8/30追記

@hikozaru_3 さんより,上の正規表現だと1+15-2のようなケースもマッチしてしまうという指摘がありました.

以下の正規表現が望ましいです.

[+-]?[0-9]+[.]?[0-9]([eE][+-])?[0-9]

また,これに併せてテスト用のスクリプトを修正したため,今まで記載していたセクションの下に修正後のものを追記します.

2017/6/22追記

@scivola さんより,1e+のような「指数もどき」もマッチしてしまうという指摘がありました.

上のものよりも以下のもののほうが望ましいかと思われます.

[+-]?[0-9]+(\.[0-9]*)?([eE][+-]?[0-9]+)?

こちらの正規表現でのテスト結果ですが,現在多忙につき割愛(もしくは後日改めて追記)させていただきます...:cry:

2018/12/2追記

.123のような小数点以下のみで数値を表現している場合は

[+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?

となるようです.

@Nabetani さんありがとうございます!!

テスト結果も編集しました.今あらためて見ると少し気持ち悪い結果もありますね。


例(正規表現にミスあり)

テスト用のスクリプト. egrep-oオプションで条件に一致した部分だけを出力する.


testscript

#!/bin/bash

file=$1

for line in `cat ${file}`
do
echo ${line}
N=`echo ${line} | egrep -o '[+-]?[0-9]+[\.]?[0-9]*[eE]?[+-]?[0-9]*'`
echo "result = ${N}"
done


で、これにこんな感じのテストケースを放り込む


testcase

1

58
-5
2.8
-3.39
73.098abh
1.0e+29
1.6E-16
abc39
num=395479.27

で、実行結果


result

>./numtest.sh testfile.txt

1
result = 1
58
result = 58
-5
result = -5
2.8
result = 2.8
-3.39
result = -3.39
73.098abh
result = 73.098
1.0e+29
result = 1.0e+29
1.6E-16
result = 1.6E-16
abc39
result = 39
num=395479.27
result = 395479.27

正しく数値だけ抜き出せてると思う


例(2018/12/2修正版)

というわけで修正したシェルスクリプトです.


testscript

#!/bin/bash

file=$1

for line in `cat ${file}`
do
echo ${line}
N=`echo ${line} | egrep -o '[+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?'`
for res in $N
do
echo "result = ${res}"
done
done


これに併せてテストケースも増やしました.今回は1つの行に複数の数値があった場合も対応できるようにしています.


testcase

1

58
-5
2.8
-3.39
73.098abh
1.0e+29
1.6E-16
abc39
num=395479.27
1+1
234gh290
432-84
235hk23.4e-6
1e+
3e-
.123
.23h5
hoge

以下,結果.


result

1

result = 1
58
result = 58
-5
result = -5
2.8
result = 2.8
-3.39
result = -3.39
73.098abh
result = 73.098
1.0e+29
result = 1.0e+29
1.6E-16
result = 1.6E-16
abc39
result = 39
num=395479.27
result = 395479.27
1+1
result = 1
result = +1
234gh290
result = 234
result = 290
432-84
result = 432
result = -84
235hk23.4e-6
result = 235
result = 23.4e-6
1e+
result = 1
3e-
result = 3
.123
result = .123
.23h5
result = .23
result = 5
hoge

今あらためて結果を確認すると、.23h5みたいなケースから.235が抜き出されるのは若干気持ち悪いですね...