CodeIQ:テキストから数値のみマスクしよう

私自身が表題の問題を解いた時のプログラムについて解説します。
問題の詳細は「テキストから数値のみマスクしよう」(CodeIQ)を参照してください。

問題の概要

問題を引用します。
あなたはとあるレポートを文章校正のため社外の機関に送るよう任されました。
ただしレポートに含まれる数値は機密情報のため、すべてマスクする必要があるとのこと。
さらに桁数すらわからないようにとのお達しのため、単純に数字(0-9)を記号に置換するだけというわけにもいきません。
そこで、テキストから数値のみを検出し、*(アスタリスク)一文字に置換するプログラムを作ることになりました。

求められるプログラムの前提条件は、以下の通りとなります。

標準入力から、制御文字を除くASCII文字のみで構成された文字列が送られる
 ※制御文字は入らないため、改行も含まれない
 文字列は80byte以下とする
 文字列に含む、すべての数値を*(アスタリスク)一文字に置き換える
 数値とは、整数・小数点数・"2.43E-19"といった指数表記による数のことを指す
 数の前に符号(-もしくは+)がある場合、符号も含めて数値とみなす
 指数表記におけるEは小文字・大文字双方とも扱うものとする
 すべての数値を*に置換した文字列を標準出力に返すこと

以下、置換例となります。

【入出力サンプル】
標準入力
x=12 y=-34.5 z=7e-8

標準出力
x=* y=* z=*

私のプログラム

Rubyで解答しています。

#!/usr/bin/ruby

# main
while line = gets
	line.strip!
	if line.empty? then next end

	puts line.gsub(/((?:\+|-)?(?:[0-9]+\.?[0-9]*(?:(?:e|E)(?:\+|-)?[0-9]+)?))/, "*")
end

解説

正規表現を使える言語なら正規表現を書けるかどうかだけの問題です。

main

ややこしい正規表現になっていますがちょっと説明します。
(?:\+|-)?は+か-が0か1個あるを表します。
(?:[0-9]+\.?[0-9]*(?:(?:e|E)(?:\+|-)?[0-9]+)?)がそのあとの数値部分です。
[0-9]+\.?[0-9]*は整数か少数を表します。1個以上の数字の並びの後に0か1個の.、そのあとに0個以上の数字の並びを判定します。←バグあり
(?:(?:e|E)(?:\+|-)?[0-9]+)?は指数表記でeかEと0か1個の±符号、1以上の数字の並びが0か1個、つまり、指数表記のe(E)以降はあってもなくても良い、ということです。
あとはこれをgsub()で全部*に置換するだけです。

雑感

テストケースには引っかかりませんでしたが、「123.」みたいなのを数値として判断してしまいます。
多分正しいのは
((?:\+|-)?(?:[0-9]+(:?\.[0-9]+)?(?:(?:e|E)(?:\+|-)?[0-9]+)?))
くらいでしょうか? 試していませんが。