数値っぽい表現を判定する正規表現を書いてみた
ググッてもすぐにヒットしなかったので、探すよりも自分で書いた方が早いと思って取り掛かったんですが、意外に時間がかかったので載せておきます。
最終的な正規表現を見るとかなりシンプルなんですが、何も考えないで書くと空文字列にマッチしたり、ドットにマッチしたりするかもしれないんで、意外にトラップが多いです。
is.numexp <- function(strs) {
grepl("(?x)^\\s*[-+]?
(?:
# begin with number
(?:
\\d+ # without commas
| (?: 0[1-9]{1,2} | 00[1-9] | [1-9]\\d{0,2} )(?: ,\\d{3} )+ # with commas
)
(?: \\.\\d* )?
# begin with dot
| \\.\\d+
)
(?i: e[-+]\\d* )? # scientific notation
\\s*$", strs, perl = TRUE)
}
ちなみに次のようなテストをしています。
01,234は数値と判定するのに0,000を数値と判定しないのは何となくそうしただけなので、気に食わない方は変更すると良いと思います。
library(RUnit)
test.is.numexp <- function() {
# 数値の文字列(16進数は対象外とする)
test.cases <- c("1234", "1234.", "1234.00000", "1234.1234", "01234",
".1234", "-1234", "+1234", " 1234", "\t1234", # 数字以外で始まる
"1234E+02", "1.234E+", "1.234E+02", "1.234e-2", ".12e+02", # 指数表記
"1,234", "01,234", "12,345,678", "123,456,789", "10,234", # カンマを含む
"1.", "1E+", "1E-", "1 ", "1\t") # 数値以外で終わる
for (test in test.cases) {
checkTrue(is.numexp(test))
}
# 数値以外の文字列
test.cases <- c("1234a", "0x123", "1,2,3", "a1234", "12.3,4", "0001,234",
"1.234+E02", "1,2345,678", "0,000", ",000", "", "e+02", ".")
for (test in test.cases) {
checkTrue(!is.numexp(test))
}
}
Perlで書くなら次のような感じでしょうか。
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
sub is_numexp {
my $str = shift;
$str =~ m{^\s*[-+]?
(?:
# begin with number
(?:
\d+ # without commas
| (?: 0[1-9]{1,2} | 00[1-9] | [1-9]\d{0,2} )(?: ,\d{3} )+ # with commas
)
(?: \.\d* )?
# begin with dot
| \.\d+
)
(?i: e[-+]\d* )? # scientific notation
\\s*$}x;
}
# 数値の文字列(16進数は対象外)
my @test_cases = (
'1234', '1234.', '1234.00000', '1234.1234', '01234',
'.1234', '-1234', '+1234', ' 1234', "\t1234", # 数字以外で始まる
'1234E+02', '1.234E+', '1.234E+02', '1.234e-2', '.12e+02', # 指数表記
'1,234', '01,234', '12,345,678', '123,456,789', '10,234', # カンマを含む
'1.', '1E+', '1E-', '1 ', "1\t", # 数値以外で終わる
);
foreach my $test (@test_cases) {
ok(is_numexp($test));
}
# 数値以外の文字列
@test_cases = (
'1234a', '0x123', '1,2,3', 'a1234', '12.3,4', '0001,234',
'1.234+E02', '1,2345,678', '0,000', ',000', '', 'e+02', '.'
);
foreach my $test (@test_cases) {
ok(!is_numexp($test));
}
done_testing;
どうぞご自由にお使いください!