1. ホーム
  2. regex

[解決済み] 浮動小数点数に対する正規表現

2022-05-05 16:16:48

質問

私は浮動小数点数のマッチングを行うタスクを持っています。私はそれのために次の正規表現を書きました。

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

しかし、エラーを返します。

Invalid escape sequence (valid ones are  \b  \t  \n  \f  \r  \"  \'  \\ )

私の知る限りでは、エスケープ文字を使って . もあります。間違っているところがあれば、訂正してください。

解決方法は?

TL;DR

使用方法 [.] の代わりに \.[0-9] ではなく \d を使用すると、一部の言語(Javaなど)でのエスケープ問題を回避することができます。

おかげさまで 名もなき者 このことを最初に認識したのは

の比較的単純なパターンを一つ。 マッチング は、より大きな文字列の中の浮動小数点数です。

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

これがマッチングします。

  • 123
  • 123.456
  • .456

をご覧ください。 動作例

もマッチングさせたい場合 123. (小数点以下のピリオド)の場合は、もう少し長い式が必要になります。

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

参照 pkellerの回答 このパターンの詳細な説明は

科学的記数法、16進数や8進数などの非10進数を含む、より広い範囲の数字を含めたい場合は、以下の回答を参照してください。 文字列が数字かどうかを識別するにはどうしたらいいですか? .

もし、あなたが バリデート 入力が数字であること (入力の中から数字を見つけるのではなく) を確認するには、そのパターンを ^$ というように。

^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$

イレギュラー 正規表現

最近のほとんどの言語、API、フレームワーク、ライブラリなどで実装されている正規表現(")は 形式言語理論 . しかし、ソフトウェア技術者は、これらの実装が正式な定義をはるかに超えるような拡張を数多く加えてきた。そのため、ほとんどの正規表現エンジンは互いに似ているが、実は標準的なものは存在しない。このため、どの言語、API、フレームワーク、ライブラリを使っているかに大きく依存することになります。

(ちなみに、混乱を避けるために、多くの人が " を使うようになりました。 レジェックス または" レジェックスプ "を使用して、これらの拡張マッチング言語を記述します。参照 Regexは正規表現と同じですか? をご覧ください(RexEgg.com)。

とはいえ、ほとんどの正規表現エンジン(実際、私が知る限りすべてのエンジン)は \. . おそらく、エスケープに問題があるのでしょう。

エスケープの問題点

いくつかの言語では、正規表現をビルトインでサポートしています。 JavaScriptのような . そうでない言語では、エスケープが問題になることがあります。

これは、基本的に言語の中の言語でコーディングすることになるからです。たとえばJavaでは \ 文字列の中にエスケープ文字としてバックスラッシュを入れる場合は、エスケープしなければなりません。

// creates a single character string: "\"
String x = "\\";

ただし、正規表現 また を使用します。 \ 文字でエスケープします。 \ 文字をエスケープした後、Javaで再度エスケープする必要があります。

// Creates a two-character string: "\\"
// When used as a regex pattern, will match a single character: "\"
String regexPattern = "\\\\";

あなたの場合、プログラミングしている言語でバックスラッシュ文字をエスケープしていないのでしょう。

// will most likely result in an "Illegal escape character" error
String wrongPattern = "\.";
// will result in the string "\."
String correctPattern = "\\.";

このようなエスケープは、非常にわかりにくいものです。もしあなたが使っている言語が 生の文字列 しかし、すべての言語がバックスラッシュの数を減らすわけではありません(特にJava)。しかし、すべての言語がそうとは限りません(特にJava)。幸いなことに、代替手段があるので、ある程度の時間はうまくいくでしょう。

String correctPattern = "[.]";

正規表現エンジンの場合。 \.[.] はまったく同じことを意味します。ただし、これはすべての場合に有効なわけではなく、例えば改行( \\n ), 開き角括弧 ( \\[ ) とバックスラッシュ ( \\\\ または [\\] ).

数字合わせの注意点

(ヒント:思ったより難しいです)

数字のマッチングは、正規表現を使えばかなり簡単だと思われがちですが、実はかなり厄介なことの一つです。あなたのアプローチをひとつひとつ見ていきましょう。

[-+]?

オプションの - または +

[0-9]*

0桁以上の連続した数字に一致する

\.?

オプションの .

[0-9]*

0桁以上の連続した数字に一致する

まず、この式を少しきれいにするために 文字クラスの省略記法 を数字に置き換えています(この場合も、前述のエスケープの問題があることに注意してください)。

[0-9] = \d

を使うことにします。 \d と同じ意味であることに注意してください。 [0-9] . (実際には、いくつかのエンジンでは \d はすべてのスクリプトの数字にマッチします。 [0-9] が、あなたの場合、それはおそらく重要ではないでしょう)。

さて、これをよく見てみると パターンのすべての部分はオプションです。 . このパターンは長さ0の文字列にマッチします。 + または - のみで構成される文字列。 . . これはおそらく、あなたが意図したものではありません。

これを解決するには、正規表現を必要最低限の文字列(おそらく1桁の数字)でアンカーリングすることから始めると便利です。

\d+

今度は小数点以下の部分を追加したいのですが、思ったようなところに行きません。

\d+\.?\d* /* This isn't quite correct. */

この場合でも、次のような値にマッチします。 123. . さらに悪いことに、これには 邪悪の色合い についてです。ピリオドはオプションです。つまり、2つの繰り返しクラスが横に並んでいることになります( \d+\d* ). これは、使い方を間違えると、システムをDoS攻撃に晒すことになり、実は危険なのです。

これを解決するには、ピリオドを省略可能として扱うのではなく、必須として扱い(繰り返される文字クラスを区切るため)、代わりに小数点以下の部分全体を省略可能として扱う必要があります。

\d+(\.\d+)? /* Better. But... */

これでよくなってきましたね。最初の数字と2番目の数字の間にピリオドが必要ですが、致命的な欠点があります。 .123 というのも、先頭の1桁が必要になってしまったからです。

これは、実はとても簡単なことなのです。数字の "decimal" の部分をオプションにする代わりに、それを一連の文字として見る必要があります。1つまたは複数の数字があり、その前に . のように、0個以上の数字が前に付くこともあります。

(\d*\.)?\d+

あとは記号を追加するだけです。

[+-]?(\d*\.)?\d+

もちろん、Javaではこのスラッシュはかなり邪魔なので、長文文字クラスで代用することができる。

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

マッチングとバリデーション

コメントで何度か話題になったので、マッチングとバリデーションについて追記します。

の目的は マッチング は、入力の中からあるコンテンツを見つけることです ("干し草の山の中の針")。一方 バリデーション は、入力が期待される形式であることを確認することです。

正規表現とは、その性質上 一致 テキストになります。入力があった場合、一致するテキストを見つけるか、見つけないかのどちらかです。しかし、アンカータグを使用して入力の最初と最後に式をスナップさせることで、( ^$ ) を使用すると、入力全体が式にマッチしない限りはマッチしないようにすることができ、効果的に正規表現を使用して バリデート .

上で説明した正規表現( [+-]?([0-9]*[.])?[0-9]+ ) は マッチ 対象文字列の中にある1つ以上の数字。つまり入力があると

apple 1.34 pear 7.98 version 1.2.3.4

正規表現がマッチするのは 1.34 , 7.98 , 1.2 , .3.4 .

入力が数字であり、数字以外の何ものでもないことを検証するには、式をアンカータグで包んで入力の開始と終了に "snap"してください。

^[+-]?([0-9]*[.])?[0-9]+$

これは、入力全体が浮動小数点数である場合にのみマッチを見つけ、入力に追加の文字が含まれる場合はマッチを見つけられません。したがって、入力が 1.2 を指定すると、マッチングが見つかりますが apple 1.2 pear にはマッチしません。

なお、一部の正規表現エンジンには validate , isMatch などの関数がありますが、これは基本的に私が説明したようなことを自動的に行い true にマッチした場合、そして false は、マッチしない場合 また、いくつかのエンジンでは、フラグを設定することで ^$ は、入力全体の開始/終了ではなく、行の開始/終了にマッチします。これは通常デフォルトではありませんが、これらのフラグに注意する必要があります。