Извлечь число из строки в Ruby

82

Я использую этот код:

s = line.match( /ABCD(\d{4})/ ).values_at( 1 )[0] 

Чтобы извлечь числа из таких строк, как:

ABCD1234
ABCD1235
ABCD1236

и т.п.

Это работает, но мне интересно, какая еще альтернатива этому есть в Ruby?

Мой код:

ids = [] 
someBigString.lines.each {|line|
   ids << line.match( /ABCD(\d{4})/ ).values_at( 1 )[0] 
}
OscarRyz
источник

Ответы:

38
a.map {|x| x[/\d+/]}
Гленн Макдональд
источник
Какая семантика, mapкак я должен это понимать? Я понимаю, collectно у меня всегда были проблемы с пониманием карты.
OscarRyz
3
@Oscar Reyes, Enumerable # map является синонимом Enumerable # collect
Уэйн Конрад,
3
К вашему сведению: если у вас есть числа, разделенные другими символами, это захватывает только первый «кусок» чисел. Таким образом, для «123ABC456» он получит только «123». Используйте что-то вроде line.gsub (/ [^ 0-9] /, ''), если хотите получить все числа.
Джошуа Пинтер,
4
также следует уточнить, что это работает с перечислимым числом, таким как массив, а не со строкой, как
требует заголовок
4
NoMethodError: неопределенный метод `map 'для String
Гарри Гомес,
177

Есть много способов Ruby согласно http://www.ruby-forum.com/topic/125709

  1. line.scan(/\d/).join('')
  2. line.gsub(/[^0-9]/, '')
  3. line.gsub(/[^\d]/, '')
  4. line.tr("^0-9", '')
  5. line.delete("^0-9")
  6. line.split(/[^\d]/).join
  7. line.gsub(/\D/, '')

Попробуйте каждый на своей консоли.

Также проверьте отчет о тестировании в этом посте.

Амит Патель
источник
24
line.delete ("^ 0-9") - самый быстрый по ссылке
Weston Ganger
62

есть еще более простое решение

line.scan(/\d+/).first
бинарный код
источник
это возвращает только первое совпадение последовательных чисел из строки. Так 'ab123cd45'.scan(/\d+/).firstбы просто вернулся12
lacostenycoder
5

Самый простой и быстрый способ - просто получить все целые числа из строки.

str = 'abc123def456'

str.delete("^0-9")
=> "123456"

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

require 'benchmark'

@string = [*'a'..'z'].concat([*1..10_000].map(&:to_s)).shuffle.join

Benchmark.bm(10) do |x|
  x.report(:each_char) do
    @string.each_char{ |c| @string.delete!(c) if c.ord<48 or c.ord>57 }
  end
  x.report(:match) do |x|
    /\d+/.match(@string).to_s
  end
  x.report(:map) do |x|
    @string.split.map {|x| x[/\d+/]}
  end
  x.report(:gsub) do |x|
    @string.gsub(/\D/, '')
  end
  x.report(:delete) do
    @string.delete("^0-9")
  end
end

             user     system      total        real
each_char    0.020000   0.020000   0.040000 (  0.037325)
match        0.000000   0.000000   0.000000 (  0.001379)
map          0.000000   0.000000   0.000000 (  0.001414)
gsub         0.000000   0.000000   0.000000 (  0.000582)
delete       0.000000   0.000000   0.000000 (  0.000060)
лакостеникодер
источник
4
your_input = "abc1cd2"
your_input.split(//).map {|x| x[/\d+/]}.compact.join("").to_i

Это должно сработать.

Рохит Патель
источник
Пожалуйста, отредактируйте свой пост, чтобы добавить больше объяснений того, что делает ваш код и почему он решает проблему. Ответ, который в основном содержит просто код (даже если он работает), обычно не поможет OP понять их проблему.
SuperBiasedMan
2

Другим решением может быть запись:

myString = "sami103"
myString.each_char{ |c| myString.delete!(c) if c.ord<48 or c.ord>57 } #In this case, we are deleting all characters that do not represent numbers.

Теперь, если вы наберете

myNumber = myString.to_i #or myString.to_f

Это должно вернуть

user2380436
источник
В общем, использование таких порядковых номеров немного опасно в качестве общего решения в эпоху многобайтовых наборов символов. В зависимости от символов, с которыми вы имеете дело, и набора символов, результаты могут быть разными в разных регионах.
Брендон Уэйтли
0

Чтобы извлечь числовую часть из строки, используйте следующее:

str = 'abcd1234'
/\d+/.match(str).try(:[], 0)

Он должен вернуться 1234

Раджеш Пол
источник
Вам не нужен matchили tryесли вы используете этот синтаксис сопоставления строкstr[/\d+/]
lacostenycoder
также .tryне является основным рубином, поэтому этот ответ не работает без active_support/core_ext/object/try.rbили рельсов
lacostenycoder 06