Extrahieren Sie die Nummer aus der Zeichenfolge in Ruby


81

Ich benutze diesen Code:

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

So extrahieren Sie Zahlen aus Zeichenfolgen wie:

ABCD1234
ABCD1235
ABCD1236

usw.

Es funktioniert, aber ich frage mich, welche andere Alternative ich dazu in Ruby habe.

Mein Code:

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

Antworten:


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

Was ist die Semantik, mapwie soll ich das verstehen? Ich verstehe, collectaber ich hatte immer Probleme, die Karte zu verstehen.
OscarRyz

3
@Oscar Reyes, Enumerable # map ist ein Synonym für Enumerable # collect
Wayne Conrad

3
Zu Ihrer Information: Wenn Sie Zahlen haben, die durch andere Zeichen aufgeteilt sind, wird nur der erste "Teil" von Zahlen erfasst. Für '123ABC456' wird also nur '123' abgerufen. Verwenden Sie so etwas wie line.gsub (/ [^ 0-9] /, ''), wenn Sie alle Zahlen erhalten möchten.
Joshua Pinter

4
sollte auch klarstellen, dass dies auf einer Aufzählung wie einem Array funktioniert, nicht auf einer Zeichenfolge, wie der Titel verlangt
Allenwlee

4
NoMethodError: undefinierte Methode `map 'für String
Garry Gomez

174

Es gibt viele Ruby-Möglichkeiten gemäß 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/, '')

Probieren Sie jeden auf Ihrer Konsole aus.

Überprüfen Sie auch den Benchmark-Bericht in diesem Beitrag.


24
line.delete ("^ 0-9") ist die schnellste gemäß dem Link
Weston Ganger

62

Es gibt noch einfachere Lösungen

line.scan(/\d+/).first

Dies gibt nur die erste Übereinstimmung aufeinanderfolgender Zahlen aus der Zeichenfolge zurück. Also 'ab123cd45'.scan(/\d+/).firstwürde 12
ich

4
your_input = "abc1cd2"
your_input.split(//).map {|x| x[/\d+/]}.compact.join("").to_i

Das sollte funktionieren.


Bitte überlegen Sie, Ihren Beitrag zu bearbeiten, um weitere Erklärungen darüber zu erhalten, was Ihr Code tut und warum er das Problem löst. Eine Antwort, die meistens nur Code enthält (auch wenn sie funktioniert), hilft dem OP normalerweise nicht, ihr Problem zu verstehen.
SuperBiasedMan

4

Der einfachste und schnellste Weg besteht darin, einfach alle ganzen Zahlen aus der Zeichenfolge herauszuholen.

str = 'abc123def456'

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

Wenn wir Benchmarks auf einer langen Reihe mit einigen der anderen hier angebotenen Lösungen vergleichen, können wir sehen, dass dies um Größenordnungen schneller ist:

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)

2

Eine andere Lösung könnte sein, zu schreiben:

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.

Nun, wenn Sie tippen

myNumber = myString.to_i #or myString.to_f

Dies sollte a zurückgeben


Im Allgemeinen ist die Verwendung solcher Ordnungszahlen als allgemeine Lösung im Zeitalter von Mehrbyte-Zeichensätzen etwas gefährlich. Abhängig von den Zeichen, mit denen Sie sich befassen, und dem Zeichensatz können die Ergebnisse an verschiedenen Orten unterschiedlich ausfallen.
Brendon Whateley

0

Verwenden Sie Folgendes, um einen Zahlenteil aus einer Zeichenfolge zu extrahieren:

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

Es sollte zurückkehren 1234


Sie brauchen nicht matchoder trywenn Sie diese String-Matching-Syntax verwendenstr[/\d+/]
lacostenycoder

auch .tryist nicht Kern Rubin so diese Antwort ohne versagt active_support/core_ext/object/try.rboder Schienen
lacostenycoder
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.