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] 
}

Respuestas:


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

¿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.


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

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)

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

Esto debería funcionar.


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


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


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.