Extraer el número de la cadena en Ruby

82

Estoy usando este código:

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

Para extraer números de cadenas como:

ABCD1234
ABCD1235
ABCD1236

etc.

Funciona, pero me pregunto qué otra alternativa tengo a esto en Ruby.

Mi código:

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

Respuestas:

38
a.map {|x| x[/\d+/]}
glenn mcdonald
fuente
¿Cuál es la semántica de mapcómo debo entenderlo? Entiendo, collectpero siempre he tenido problemas para entender el mapa.
OscarRyz
3
@Oscar Reyes, Enumerable # map es sinónimo de Enumerable # collect
Wayne Conrad
3
FYI: Si tiene números divididos por otros caracteres, esto solo toma el primer "trozo" de números. Entonces, para '123ABC456', solo tomará '123'. Use algo como line.gsub (/ [^ 0-9] /, '') si desea obtener todos los números.
Joshua Pinter
4
también debe aclarar que esto funciona en un enumerable como una matriz, no una cadena como pide el título
allenwlee
4
NoMethodError: método indefinido `mapa 'para String
Garry Gomez
177

Hay muchas formas de Ruby según 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/, '')

Pruebe cada uno en su consola.

También consulte el informe de referencia en esa publicación.

Amit Patel
fuente
24
line.delete ("^ 0-9") es el más rápido según el enlace
Weston Ganger
62

hay una solución aún más simple

line.scan(/\d+/).first
código binario
fuente
esto solo devuelve la primera coincidencia de números consecutivos de la cadena. Así 'ab123cd45'.scan(/\d+/).firstque volvería12
lacostenycoder
5

La forma más sencilla y rápida es simplemente sacar todos los enteros de la cadena.

str = 'abc123def456'

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

Al comparar los puntos de referencia en una cadena larga con algunas de las otras soluciones proporcionadas aquí, podemos ver que esto es órdenes de magnitud más rápido:

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

Esto debería funcionar.

Rohit Patel
fuente
Considere editar su publicación para agregar más explicaciones sobre lo que hace su código y por qué resolverá el problema. Una respuesta que en su mayoría solo contiene código (incluso si está funcionando) generalmente no ayudará al OP a comprender su problema.
SuperBiasedMan
2

Otra solución puede ser escribir:

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.

Ahora, si escribe

myNumber = myString.to_i #or myString.to_f

Esto debería devolver un

usuario2380436
fuente
En general, el uso de ordinales como este es un poco peligroso como solución general en la era de los conjuntos de caracteres multibyte. Dependiendo de los personajes con los que esté tratando y el conjunto de caracteres, las cosas podrían obtener diferentes resultados en diferentes lugares.
Brendon Whateley
0

Para extraer la parte numérica de una cadena, use lo siguiente:

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

Debería volver 1234

Rajesh Paul
fuente
No necesita matcho trysi usa esta sintaxis de coincidencia de cadenasstr[/\d+/]
lacostenycoder
tampoco .tryes core ruby, por lo que esta respuesta falla sin active_support/core_ext/object/try.rbo rieles
lacostenycoder