1. ホーム
  2. regex

[解決済み] テキスト中のカンマや小数のある数字にマッチする正規表現

2022-09-21 23:42:04

質問

私は、テキストの本文中にあるすべての数字を検索して置き換えようとしています。 私はいくつかの例の正規表現を見つけました、それはほとんど問題を解決しますが、どれもまだ完璧ではありません。 私が抱えている問題は、テキスト内の数字が小数点とカンマを持つか持たないかということです。 例えば

5000ポンドのキツネは99,999.99998713フィートのフェンスを飛び越えた."

正規表現は " を返す必要があります。 5000 "と " 99,999.99998713 "です。 私が見つけた例では、コンマで数字が分割されていたり、小数点以下が2桁に制限されています。 私は正規表現を十分に理解し始めているので、なぜいくつかの例が小数点以下2桁に制限されているのかがわかりますが、それを克服し、カンマも含めて全体のシーケンスを取得する方法はまだ学んでいません。

これが私の最新バージョンです。

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

どちらが返すかというと、"。 5000 "、" 99,99 "、" 9.99 "、および " 998713 "を使用します。

どのように解決するのですか?

EDIT: これは多くのビューを得たので、私は彼らがググったものを皆に与えることから始めましょう。

#ALL THESE REQUIRE THE WHOLE STRING TO BE A NUMBER
#For numbers embedded in sentences, see discussion below

#### NUMBERS AND DECIMALS ONLY ####
#No commas allowed
#Pass: (1000.0), (001), (.001)
#Fail: (1,000.0)
^\d*\.?\d+$

#No commas allowed
#Can't start with "."
#Pass: (0.01)
#Fail: (.01)
^(\d+\.)?\d+$

#### CURRENCY ####
#No commas allowed
#"$" optional
#Can't start with "."
#Either 0 or 2 decimal digits
#Pass: ($1000), (1.00), ($0.11)
#Fail: ($1.0), (1.), ($1.000), ($.11)
^\$?\d+(\.\d{2})?$

#### COMMA-GROUPED ####
#Commas required between powers of 1,000
#Can't start with "."
#Pass: (1,000,000), (0.001)
#Fail: (1000000), (1,00,00,00), (.001)
^\d{1,3}(,\d{3})*(\.\d+)?$

#Commas required
#Cannot be empty
#Pass: (1,000.100), (.001)
#Fail: (1000), ()
^(?=.)(\d{1,3}(,\d{3})*)?(\.\d+)?$

#Commas optional as long as they're consistent
#Can't start with "."
#Pass: (1,000,000), (1000000)
#Fail: (10000,000), (1,00,00)
^(\d+|\d{1,3}(,\d{3})*)(\.\d+)?$

#### LEADING AND TRAILING ZEROES ####
#No commas allowed
#Can't start with "."
#No leading zeroes in integer part
#Pass: (1.00), (0.00)
#Fail: (001)
^([1-9]\d*|0)(\.\d+)?$

#No commas allowed
#Can't start with "."
#No trailing zeroes in decimal part
#Pass: (1), (0.1)
#Fail: (1.00), (0.1000)
^\d+(\.\d*[1-9])?$

さて、それはさておき、以下のほとんどは、正規表現を賢く使おうとするとどれだけ複雑になるか、そしてなぜ代替手段を探すべきなのかについての解説を意味しています。ご自分の責任でお読みください。


これは非常に一般的なタスクですが、これまでにここで見たすべての回答は、次のようなあなたの数値フォーマットに一致しない入力を受け付けます。 ,111 , 9,9,9 あるいは .,,. . これは、たとえ数字が他のテキストに埋め込まれていたとしても、修正するのは簡単なことです。IMHOは、1,234.56と1234-を引き出せないものは と、これらの数字だけ -のうち abc22 1,234.56 9.9.9.9 def 1234 は誤答です。

まず第一に、もしこれを一つの正規表現ですべて行う必要がないのであれば、そうしないことです。2つの異なる数値フォーマットに対して1つの正規表現を使用すると、他のテキストに埋め込まれていない場合でも、メンテナンスが大変です。本当は、全体を空白で分割して、その結果に対して2つか3つの小さな正規表現を実行すべきなのです。もしそれがあなたにとって選択肢でないなら、読み進めてください。

基本的なパターン

あなたが挙げた例を考慮し、以下のようなシンプルな正規表現があります。 0000 形式で、それ以外のものはすべてブロックします。

^\d*\.?\d+$

以下は 0,000 の書式が必要です。

^\d{1,3}(,\d{3})*(\.\d+)?$

これらをまとめると、一貫性がある限り、カンマは省略可能になります。

^(\d*\.?\d+|\d{1,3}(,\d{3})*(\.\d+)?)$

埋め込みの数字

上記のパターンは、入力全体が数字であることを要求しています。テキストに埋め込まれた数字を探すわけですから、その部分を緩める必要があります。一方、入力された文字列から catch22 を見て、22という数字を見つけたと勘違いされては困ります。もしあなたが(.NETのような)ルックビハインドサポートを使っているなら、これはとても簡単なことです。 ^(?<!\S)$(?!\S) と入力すればOKです。

(?<!\S)(\d*\.?\d+|\d{1,3}(,\d{3})*(\.\d+)?)(?!\S)

JavaScriptやRubyなどを使っている場合、物事はより複雑に見え始めます。

(?:^|\s)(\d*\.?\d+|\d{1,3}(?:,\d{3})*(?:\.\d+)?)(?!\S)

キャプチャグループを使う必要があります。lookbehindのサポートがないため、代替手段を思いつきません。必要な数値はグループ 1 になります (マッチ全体がグループ 0 であると仮定します)。

バリデーションとより複雑なルール

これであなたの疑問は解決したと思いますので、それでよければ今すぐ読むのをやめてください。もっと複雑なことをしたい場合は、物事が非常に複雑になるのが非常に速いです。あなたの状況に応じて、以下のいずれか、またはすべてをブロックする必要があるかもしれません。

  • 空の入力
  • 先頭のゼロ(例:000123)
  • 末尾のゼロ(例:1.2340000)
  • 小数点から始まる小数(例:0.001に対して.001)

念のため、最初の 3 つをブロックし、最後の 1 つを許可したいと仮定します。どうすればよいのでしょうか。ルールごとに異なる正規表現を使用し、マッチを徐々に絞り込む必要があります。しかし、チャレンジのために、ここでは一つの巨大なパターンですべてを行う方法を紹介します。

(?<!\S)(?=.)(0|([1-9](\d*|\d{0,2}(,\d{3})*)))?(\.\d*[1-9])?(?!\S)

そして、その意味はこうだ。

(?<!\S) to (?!\S) #The whole match must be surrounded by either whitespace or line boundaries. So if you see something bogus like :;:9.:, ignore the 9.
(?=.)             #The whole thing can't be blank.

(                    #Rules for the integer part:
  0                  #1. The integer part could just be 0...
  |                  #
  [1-9]              #   ...otherwise, it can't have leading zeroes.
  (                  #
    \d*              #2. It could use no commas at all...
    |                #
    \d{0,2}(,\d{3})* #   ...or it could be comma-separated groups of 3 digits each.
  )                  # 
)?                   #3. Or there could be no integer part at all.

(       #Rules for the decimal part:
  \.    #1. It must start with a decimal point...
  \d*   #2. ...followed by a string of numeric digits only.
  [1-9] #3. It can't be just the decimal point, and it can't end in 0.
)?      #4. The whole decimal part is also optional. Remember, we checked at the beginning to make sure the whole thing wasn't blank.

ここでテストしたのは http://rextester.com/YPG96786

というようなことが可能になります。

100,000
999.999
90.0009
1,000,023.999
0.111
.111
0

などをブロックしてくれます。

1,1,1.111
000,001.111
999.
0.
111.110000
1.1.1.111
9.909,888

この正規表現をよりシンプルで短くする方法はいくつかありますが、パターンを変更すると、何を数字とみなすかが緩くなることを理解しておいてください。

多くの正規表現エンジン(JavaScriptやRubyなど)は負のlookbehindをサポートしていないため、これを正しく行う唯一の方法はキャプチャグループを使うことです。

(?:^|\s)(?=.)((?:0|(?:[1-9](?:\d*|\d{0,2}(?:,\d{3})*)))?(?:\.\d*[1-9])?)(?!\S)

探している数値は、キャプチャグループ1になります。

ここでテストした http://rubular.com/r/3HCSkndzhT

最後の注意

明らかに、これは巨大で、複雑で、とても読めない正規表現です。私はこのチャレンジを楽しみましたが、あなたは これを本当に実稼働環境で使用したいのかどうか考えてみてください。 1 つのステップですべてを実行しようとするのではなく、2 つのステップで実行することができます。 をキャッチする正規表現。 をキャッチするための正規表現、そして でないものは でないものを排除するために、もう1つの処理を行います。あるいは、基本的な処理をしてから、言語に組み込まれた数値解析の機能を使うこともできます。お好みでどうぞ。