Витяг номера із рядка в 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] 
}

Відповіді:


38
a.map {|x| x[/\d+/]}

Яка семантика того, mapяк я повинен це розуміти? Я розумію, collectале у мене завжди були проблеми з розумінням карти.
OscarRyz

3
@Oscar Reyes, Enumerable # map є синонімом для Enumerable # collect
Wayne Conrad

3
FYI: Якщо у вас є числа, розділені на інші символи, це захоплює лише перший "шматок" чисел. Тож для '123ABC456' він буде захоплювати лише '123'. Використовуйте щось на зразок line.gsub (/ [^ 0-9] /, ''), якщо хочете отримати всі числа.
Джошуа Пінтер

4
слід також пояснити, що це працює з таким числом, як масив, а не рядок, як просить заголовок
allenwlee

4
NoMethodError: undefined method `map 'for String
Garry Gomez

177

Відповідно до http://www.ruby-forum.com/topic/125709, існує багато способів Ruby

  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


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

Це має спрацювати.


Будь ласка, подумайте про редагування вашого допису, щоб додати більше пояснень щодо того, що робить ваш код, і чому це вирішить проблему. Відповідь, яка здебільшого містить лише код (навіть якщо він працює), як правило, не допомагає ОП зрозуміти свою проблему.
SuperBiased,

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

Це повинно повернути a


Загалом, використання таких порядкових знаків є трохи небезпечним як загальне рішення у вік багатобайтових наборів символів. Залежно від персонажів, з якими ви маєте справу, та набору символів, речі можуть мати різні результати в різних регіонах.
Brendon Whateley

0

Щоб витягти числову частину з рядка, використовуйте наступне:

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

Він повинен повернутися 1234


Вам не потрібно, matchабо tryякщо ви використовуєте цей синтаксис, що відповідає рядкуstr[/\d+/]
lacostenycoder

також .tryне є основним рубіном, тому ця відповідь не вдається без active_support/core_ext/object/try.rbабо рейок
lacostenycoder
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.