Сканирование регулярных выражений не удается - PullRequest
0 голосов
/ 15 февраля 2019

Я пытаюсь разобрать все деньги из строки.Например, я хочу извлечь:

['$250,000', '$3.90', '$250,000', '$500,000']

из:

'Up to $250,000………………………………… $3.90 Over $250,000 to $500,000'

Регулярное выражение:

\$\ ?(\d+\,)*\d+(\.\d*)?

, кажется, соответствует всем денежным выражениям, как в эта ссылка .Однако, когда я пытаюсь scan на Ruby, он не дает желаемого результата.

s # => "Up to $250,000 $3.90 Over $250,000 to $500,000, add$3.70 Over $500,000 to $1,000,000, add..$3.40 Over $1,000,000 to $2,000,000, add...........$2.25\nOver $2,000,000 add ..$2.00"
r # => /\$\ ?(\d+\,)*\d+\.?\d*/
s.scan(r)
# => [["250,"], [nil], ["250,"], ["500,"], [nil], ["500,"], ["000,"], [nil], ["000,"], ["000,"], [nil], ["000,"], [nil]]

Из String#scan документов, похоже, что это из-за группы.Как я могу разобрать все деньги в строке?

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Давайте посмотрим на ваше регулярное выражение, которое я напишу в режиме свободного пробела , чтобы я мог его документировать:

r = /
    \$     # match a dollar sign
    \ ?    # optionally match a space (has no effect) 
    (      # begin capture group 1
      \d+  # match one or more digits
      ,    # match a comma (need not be escaped)
    )*     # end capture group 1 and execute it >= 0 times
    \d+    # match one or more digits
    \.?    # optionally match a period
    \d*    # match zero or more digits
    /x     # free-spacing regex definition mode

В режиме без свободного пробела это будетзаписывается следующим образом.

r = /\$ ?(\d+,)*\d+\.?\d*/

Когда регулярное выражение определено в режиме свободного пробела, все пробелы удаляются перед его вычислением, поэтому мне пришлось покинуть пространство.В этом нет необходимости, если регулярное выражение не определено в режиме свободного пространства.

Не нужно совпадать с пробелом после знака доллара, поэтому \ ? следует удалить.Предположим, теперь у нас есть

r = /\$\d+\.?\d*/
"$2.31 cat $44. dog $33.607".scan r
  #=> ["$2.31", "$44.", "$33.607"]

Это работает, но сомнительно, хотите ли вы сопоставить значения, которые не имеют ровно две цифры после десятичной точки.

Теперь напишите

r = /\$(\d+,)*\d+\.?\d*/
"$2.31 cat $44. dog $33.607".scan r
  #=> [[nil], [nil], [nil]]

Чтобы понять, почему был получен этот результат, изучите документ для String # scan , в частности, последнее предложение первого абзаца: «Если шаблон содержит группы, каждый отдельный результат сам является массивом, содержащимодна запись на группу.

Мы можем избежать этой проблемы, изменив группу захвата на группу без захвата:

r = /\$(?:\d+,)*\d+\.?\d*/
"$2.31 cat $44. dog $33.607".scan r
  #=> ["$2.31", "$44.", "$33.607"] 

Теперь рассмотрим это:

"$2,241.31 cat $1,2345. dog $33.607".scan r
  #=> ["$2,241.31", "$1,2345.", "$33.607"]

, что до сих пор не совсемправо.Попробуйте следующее.

r = /
    \$          # match a dollar sign
    \d{1,3}     # match one to three digits
    (?:,\d{3})  # match ',' then 3 digits in a nc group
    *           # execute the above nc group >=0 times
    (?:\.\d{2}) # match '.' then 2 digits in a nc group
    ?           # optionally match the above nc group
    (?![\d,.])  # no following digit, ',' or '.'
    /x          # free-spacing regex definition mode

"$2,241.31 $2 $1,234 $3,6152 $33.607 $146.27".scan r
  #=> ["$2,241.31", "$2", "$1,234", "$146.27"]

(?![\d,.]) является негативным прогнозом .

В обычном режиме это регулярное выражение записывается следующим образом.

r = /\$\d{1,3}(?:,\d{3})*(?:\.\d{2})?(?![\d,.])/

Следующий ошибочный результат будет получен без отрицательного просмотра в конце регулярного выражения.

r = /\$\d{1,3}(?:,\d{3})*(?:\.\d{2})?/
"$2,241.31 $2 $1,234 $3,6152 $33.607 $146.27".scan r
  #=> ["$2,241.31", "$2", "$1,234", "$3,615", "$33.60",
  #    "$146.27"]
0 голосов
/ 15 февраля 2019
[3] pry(main)> str = <<EOF
[3] pry(main)* Up to $250,000………………………………… $3.90 Over $250,000 to $500,000, add………………$3.70 Over $500,000 to $1,000,000, add……………..$3.40 Over $1,000,000 to $2,000,000, add……...........$2.25
[3] pry(main)* Over $2,000,000 add …..………………………$2.00
[3] pry(main)* EOF
=> "Up to $250,000………………………………… $3.90 Over $250,000 to $500,000, add………………$3.70 Over $500,000 to $1,000,000, add……………..$3.40 Over $1,000,000 to $2,000,000, add……...........$2.25\nOver $2,000,000 add …..………………………$2.00\n"
[4] pry(main)> str.scan /\$\d+(?:[,.]\d+)*/
=> ["$250,000", "$3.90", "$250,000", "$500,000", "$3.70", "$500,000", "$1,000,000", "$3.40", "$1,000,000", "$2,000,000", "$2.25", "$2,000,000", "$2.00"]
[5] pry(main)>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...