Wyodrębnij liczbę z łańcucha w Rubim

82

Używam tego kodu:

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

Aby wyodrębnić liczby z ciągów, takich jak:

ABCD1234
ABCD1235
ABCD1236

itp.

Działa, ale zastanawiam się, jaką inną alternatywę mam do tego w Rubim?

Mój kod:

ids = [] 
someBigString.lines.each {|line|
   ids << line.match( /ABCD(\d{4})/ ).values_at( 1 )[0] 
}
OscarRyz
źródło

Odpowiedzi:

38
a.map {|x| x[/\d+/]}
glenn mcdonald
źródło
Jaka jest semantyka tego, mapjak mam to rozumieć? Rozumiem, collectale zawsze miałem problem ze zrozumieniem mapy.
OscarRyz,
3
@Oscar Reyes, Enumerable # map jest synonimem Enumerable # collect
Wayne Conrad
3
FYI: Jeśli masz liczby podzielone na inne znaki, to pobiera tylko pierwszy „fragment” liczb. Tak więc dla „123ABC456” będzie pobierać tylko „123”. Użyj czegoś takiego jak line.gsub (/ [^ 0-9] /, ''), jeśli chcesz uzyskać wszystkie liczby.
Joshua Pinter
4
Powinien również wyjaśnić, że działa to na wyliczalnych, takich jak tablica, a nie na łańcuchu, o który pyta tytuł
allenwlee
4
NoMethodError: undefined method `map 'for String
Garry Gomez
177

Jest wiele sposobów na Rubiego, jak na 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/, '')

Wypróbuj każdy na swojej konsoli.

Sprawdź również raport porównawczy w tym poście.

Amit Patel
źródło
24
line.delete ("^ 0-9") jest najszybsze zgodnie z linkiem
Weston Ganger
62

jest jeszcze prostsze rozwiązanie

line.scan(/\d+/).first
kod binarny
źródło
zwraca to tylko pierwsze dopasowanie kolejnych liczb z ciągu. Więc 'ab123cd45'.scan(/\d+/).firstpo prostu wrócę12
lacostenycoder
5

Najprostszym i najszybszym sposobem jest po prostu usunięcie wszystkich liczb całkowitych z łańcucha.

str = 'abc123def456'

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

Porównując testy porównawcze na długim łańcuchu z niektórymi innymi przedstawionymi tutaj rozwiązaniami, widzimy, że jest to szybsze o rząd wielkości:

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)
lacostenycoder
źródło
4
your_input = "abc1cd2"
your_input.split(//).map {|x| x[/\d+/]}.compact.join("").to_i

To powinno działać.

Rohit Patel
źródło
Rozważ edycję swojego posta, aby dodać więcej wyjaśnień na temat tego, co robi Twój kod i dlaczego rozwiąże problem. Odpowiedź, która w większości zawiera tylko kod (nawet jeśli działa), zazwyczaj nie pomoże OP w zrozumieniu problemu.
SuperBiasedMan
2

Innym rozwiązaniem może być napisanie:

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.

Teraz, jeśli piszesz

myNumber = myString.to_i #or myString.to_f

Powinno to zwrócić plik

user2380436
źródło
Ogólnie rzecz biorąc, używanie takich liczb porządkowych jest trochę niebezpieczne jako ogólne rozwiązanie w dobie wielobajtowych zestawów znaków. W zależności od postaci, z którymi masz do czynienia i zestawu znaków, rzeczy mogą mieć różne wyniki w różnych lokalizacjach.
Brendon Whateley
0

Aby wyodrębnić część liczbową z ciągu, użyj:

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

Powinien powrócić 1234

Rajesh Paul
źródło
Nie potrzebujesz matchlub tryjeśli używasz tej składni pasującej do ciągustr[/\d+/]
lacostenycoder,
również .trynie jest rdzeń Ruby więc ta odpowiedź nie bez active_support/core_ext/object/try.rblub szyn
lacostenycoder