浮動小数点数の正規表現


115

浮動小数点数を照合するタスクがあります。次の正規表現を記述しました。

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

しかし、それはエラーを返します:

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

私の知る限りでは、エスケープ文字.もに使用する必要があります。間違っている箇所を修正してください。


10
この正規表現はどの言語で使用されていますか?
CaffGeek 2012

3
@JDB-数値/浮動小数点正規表現に100ポイントを与えるのはなぜですか?標準は常に(?:\d+(?:\.\d*)?|\.\d+)そうであり、SOに無限に投稿されています...


1
[-+]?([0-9]*[.])?[0-9]+([eE][-+]?\d+)?指数表記も使用したい場合(例:3.023e-23
wcochran

JavaやC ++などの一部の言語では、円記号をエスケープする必要があります。したがって、正規表現「\。」を取得するには、文字列「\\。」を使用します。Pythonは生の文字列を使用してこれを回避します。
HackerBoss

回答:


258

TL; DR

一部の言語(Javaなど)でエスケープの問題を回避するために、[.]代わりに\.およびの[0-9]代わりに使用し\dます。

もともとこれを認識しくれた無名の方に感謝します。

浮動小数点数を照合するための比較的単純なパターンの1つは、

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

これは一致します:

  • 123
  • 123.456
  • .456

実際の例を見る

123.(小数部のないピリオド)も一致させたい場合は、少し長い式が必要になります。

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

このパターンの詳しい説明については、pkellerの回答を参照してください

16進数や8進数などの10進数以外の数値を含める場合は、「文字列が数値かどうかを確認するにはどうすればよいですか?」に対する私の回答を参照してください

入力が数値であることを検証したい場合は(入力内の数値を見つけるのではなく)、次のようにパターンを^and $で囲む必要があります。

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

不規則な正規表現

「正規表現」は、ほとんどの現代の言語、API、フレームワーク、ライブラリなどで実装されており、正式な言語理論で開発された概念に基づいています。ただし、ソフトウェアエンジニアは、これらの実装を正式な定義をはるかに超える多くの拡張機能を追加しています。したがって、ほとんどの正規表現エンジンは互いに似ていますが、実際には標準はありません。このため、使用している言語、API、フレームワーク、またはライブラリに大きく依存します。

(ちなみに、混乱を減らすために、多くの人が " regex "または " regexp "を使用してこれらの拡張一致言語を記述しています。詳細については、 RexEgg.comのRegexは正規表現と同じですか?を参照してください。)

そうは言っても、ほとんどの正規表現エンジン(実際には、私が知る限り、すべてのエンジン)が受け入れ\.ます。ほとんどの場合、エスケープに問題があります。

脱出のトラブル

一部の言語には、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)。幸いなことに、時々動作する代替手段があります:

String correctPattern = "[.]";

正規表現エンジンの場合\.[.]まったく同じ意味です。これは、改行(\\n)、開き角括弧(\\[)、バックスラッシュ(\\\\または[\\])のように、すべての場合で機能するわけではないことに注意してください。

番号の一致に関する注意

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

数を一致させることは、正規表現を使用すると非常に簡単だと思うことの1つですが、実際にはかなりトリッキーです。あなたのアプローチを少しずつ見てみましょう:

[-+]?

オプション-または+

[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ます。先行する数字が必要になるため、一致できません。

これは実際には簡単に修正できます。数値の「10進数」の部分をオプションにする代わりに、文字のシーケンスとして.見なす必要があります。

(\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.347.981.2.3.4

指定された入力が数値であり、数値にすぎないことを検証するには、アンカータグでラップして、式を入力の開始と終了に「スナップ」します。

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

これは、入力全体が浮動小数点数の場合にのみ一致を検出し、入力に追加の文字が含まれている場合には一致を検出しません。したがって、入力1.2が与えられるとapple 1.2 pear一致が見つかりますが、一致が見つからないことになります。

一部の正規表現エンジンにはvalidateisMatchまたは同様の機能があり、基本的には私が説明したことを自動的に実行し、true一致が見つかった場合と一致が見つからfalseなかった場合に返されます。また、一部のエンジンでは^、およびの定義を変更するフラグを設定し$て、入力全体の先頭/末尾ではなく、行の先頭/末尾に一致させることができることにも注意してください。通常、これはデフォルトではありませんが、これらのフラグに注意してください。


2
JDBさん、ありがとうございます。私は確かに0.24と2.2の世話をするあなたの答え:)将来的にあなたの記事を読んで、正しく4.2.44すべてでテスト禁止していますregex101.comしかし、それは(と私はそれを考えるあなたが許容できる言うように123を禁止しますです!)。これを修正するには、式を[-+]?(\ d * [。])?\ d *(+ではなく最後に*と表示)に変更しますが、のようにクレイジーです。(2番目の例)は許可されます。とにかく私のケーキを持って食べますか?
デイブ

2
@Dave -\d+(\.\d*)?|\.\d+
JDBはまだモニカ覚え

/[-+]?(\d*[.])?\d+/.test("1.bc") // returns true
yeouuu 2016

1
@yeouuuはい、1.一致します。入力全体が一致する場合にのみ一致させたい場合は、正規表現の最初と最後に^and $を追加します。
JDBは

5
浮動小数点数は指数を持つか、NaN / Infにすることができる[-+]?(([0-9]*[.]?[0-9]+([ed][-+]?[0-9]+)?)|(inf)|(nan))ため、浮動小数点数/倍精度浮動小数点数の場合は、e / dを使用します 。正規表現へのフォールドケースフラグを忘れないでください
Markus Schmassmann

23

執筆時点でのこのページの回答のいずれも正しいとは思いません(SOに関する他の多くの提案も間違っています)。複雑なのは、次のすべての可能性を一致させる必要があることです。

  • 小数点なし(つまり、整数値)
  • 小数点の前と後の両方の数字(例えば0.3522.165
  • 小数点の前の数字のみ(例えば0.1234.
  • 小数点以下の桁のみ(例.0.5678

同時に、少なくとも1つの数字がどこかにあることを確認する必要があります。つまり、以下は許可されません。

  • 小数点自体
  • 数字のない符号付き小数点(つまり+.または-.
  • +または-自分で
  • 空の文字列

これは最初はトリッキーに見えますが、インスピレーションを見つける1つの方法は、java.lang.Double.valueOf(String)メソッドのOpenJDKソースを確認することです(http://hg.openjdk.java.net/jdk8/jdk8/jdkから開始し、[参照]をクリックして、下に移動します)クラス/src/share/classes/java/lang/を見つけますDouble)。このクラスに含まれる長い正規表現は、OPがおそらく考えていなかったさまざまな可能性に対応していますが、NaN、無限大、16進表記および指数を処理する部分を単純化して無視し\d、POSIX表記ではなく1桁の場合、指数を使用せずに、符号付き浮動小数点数の正規表現の重要な部分を減らすことができます。

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

(...)|(...)数字を含まないものを許可したり、小数点の前に数字がない、またはその後に数字がない可能性の1つを禁止せずに構成を回避する方法はないと思います。

明らかに実際には、正規表現自体またはそれを使用するコードのいずれかで、末尾または先行の空白に対応する必要があります。


のような数値に一致するという要件を追加した場合123.、はい... 元の投稿のコメントで指摘したように、またはスイッチが唯一の解決策です。
JDBは2017

1
これ、および他のほとんどすべての答えは、フロートが指数を持つことができることを無視します。
NateS 2017年

1
@NateSそうです、私は「NaN、無限大、16進表記、および指数を処理する部分を単純にするために無視する」と書きました。これは、OPの質問の範囲と一致しているようです。JDKソースコードで見つけたものを含め、より完全な実装があります。
pkeller

1
正規表現[+-]?((?=\.?\d)\d*\.?\d*)を使用して代替を回避できますか?先読みを使用します...
4esn0k

1
@ 4esn0kいい正規表現!私はそれをいじってみましたが、うまくいきます。私は2つの注意点を持っています:(1)すべての正規表現エンジンがゼロ幅アサーションをサポートしているわけではありません(ほとんどの最新のものはAFAIKがサポートしています)、そして(2)先読みは別の名前による単なる代替です:エンジンはまだ何かを試さなければなりません機能しない場合はバックトラックします。それにもかかわらず、非常にきちんとしたアイデアに賛成票を投じます。
pkeller

7

あなたが必要なものは:

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

「+」と「-」の記号をエスケープし、「1」のようなものから10進数とそれに続く数字をグループ化しました。は有効な数値ではありません。

変更により、整数と浮動小数点を一致させることができます。例えば:

0
+1
-2.0
2.23442

この式の問題は、その.1ような入力が一般に正しいと認識されていても、許可されないことです。
JDBは2012

これは、長さ0の文字列-+、数字ではないを受け入れます。正規表現はトリッキーです!:)
JDBはモニカを2012

また、これはOPの実際の質問には答え\.ません。つまり、それは機能しません。
JDBはモニカを2012

7

ほとんどの言語が有効な数値と見なすもの(整数と浮動小数点数)に一致させたい:

  • '5' / '-5'

  • '1.0' / '1.' / '.1' / '-1.' / '-.1'

  • '0.45326e+04', '666999e-05', '0.2e-3', '-33.e-1'

ノート:

  • preceding sign of number ('-' or '+') is optional

  • '-1.' and '-.1' are valid but '.' and '-.' are invalid

  • '.1e3' is valid, but '.e3' and 'e3' are invalid

両方をサポートするために、「1」。また、「。1」を除外するには、OR演算子(「|」)が必要です。マッチングから。

[+-]?+/- ?は0または1が一致することを意味するため、オプションで歌う

( 2つのサブ式があるので、括弧で囲む必要があります

\d+([.]\d*)?(e[+-]?\d+)? これは数字で始まる数字用です

| サブ式を区切ります

[.]\d+(e[+-]?\d+)? これは「。」で始まる番号用です。

) 式の終わり

  • 「。」で始まる番号の場合

[.] 最初の文字はドット(角かっこ内またはワイルドカード文字)

\d+ 1桁以上

(e[+-]?\d+)? これはオプションです(末尾の「?」による0または1の一致)科学表記

  • 数字で始まる数字の場合

\d+ 1桁以上

([.]\d*)? オプションで、ドット文字の後にゼロまたはそれ以上の桁を置くことができます

(e[+-]?\d+)? これはオプションの科学表記法です

  • 科学表記

e 指数を指定するリテラル

[+-]? オプションの指数記号

\d+ 1桁以上

これらすべてを組み合わせると:

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

E同様に受け入れるには:

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

テストケース


4

これは簡単です。Javaを使用\\.していて、\.(Javaで文字エスケープを検索する)の代わりに使用する必要があります。


おそらく正しい...エラーメッセージは、正規表現パーサーエラーではなく、プログラミング言語の構文エラーのように見えます。
JDBは、モニカの2016

3

これは私のために働きました:

(?P<value>[-+]*\d+\.\d+|[-+]*\d+)

これも(名前付きパラメーターなしで)使用できます。

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

オンライン正規表現テスターを使用してテストします(例:regex101)


2
^[+]?([0-9]{1,2})*[.,]([0-9]{1,1})?$

これは一致します:

  1. 1.2
  2. 12.3
  3. 1,2
  4. 12,3

このコードスニペットは歓迎されており、多少の助けになるかもしれませんが、これが問題を解決する方法理由の説明含めると、大幅に改善されます。あなたが今尋ねている人だけでなく、将来の読者のための質問に答えていることを忘れないでください!回答を編集して説明を追加し、適用される制限と前提を示してください。
Toby Speight 2017

ああ、そうそう、私はこれを探しています
Serg Burlaka

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

[+-]? -オプションの先行記号

(([1-9][0-9]*)|(0)) -単一のゼロを含む、先行ゼロのない整数

([.,][0-9]+)? -オプションの小数部


1
より多くの情報を与える-正規表現を知らない人にとってはそれはヒエログリフです。それらを知っている人々にとって、彼らはそれを必要としません。
peterh-モニカを2015年

0

正規表現ライブラリを使用するC ++

答えはこのようになります:

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

私が記号をとらないことに注意してください、もしあなたが記号と一緒にそれを望めば、それはこれについて行くでしょう:

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

これにより、通常の数値または10進数も分離されます。


0

C表記では、浮動小数点数は次の形状で発生する可能性があります。

  1. 123
  2. 123。
  3. 123.24
  4. .24
  5. 2e-2 = 2 * 10 pow -2 = 2 * 0.1
  6. 4E + 4 = 4 * 10 pow 4 = 4 * 10 000

float正規表現を作成するには、まず「int正規表現変数」を作成します。

(([1-9][0-9]*)|0) will be int

ここで、フロート正規表現の小さなチャンクを記述します-解決策は、それらのチャンクをorまたは「|」で連結することです。

チャンク:

- (([+-]?{int}) satysfies case 1
- (([+-]?{int})"."[0-9]*)  satysfies cases 2 and 3
- ("."[0-9]*) satysfies case 4
- ([+-]?{int}[eE][+-]?{int}) satysfies cases 5 and 6

最終的な解決策(小さなチャンクの連結):

(([+-]?{int})|(([+-]?{int})"."[0-9]*)|("."[0-9]*)|([+-]?{int}[eE][+-]?{int})


-1

JavaScript用

const test = new RegExp('^[+]?([0-9]{0,})*[.]?([0-9]{0,2})?$','g');

これは1.23で機能します1234.22 0 0.12 12

の部分を変更して{}、小数部の長さと小数部の前部でも異なる結果を得ることができます。これは、数字を入力するために入力で使用され、通過するものだけを許可して入力するときにすべての入力をチェックします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.