ruby - ultimos - ¿Cuál es la forma más fácil de eliminar el primer carácter de una cadena?
excel quitar primera letra (14)
¡Gracias a @ the-tin-man por armar los puntos de referencia!
Por desgracia, realmente no me gusta ninguna de esas soluciones. O requieren un paso adicional para obtener el resultado ( [0] = ''''
, .strip!
) O no son muy semánticos / claros sobre lo que está sucediendo ( [1..-1]
: "Um, un rango de 1 a 1 negativo? Yearg? "), o son lentos o largos de escribir ( .gsub
, .length
).
Lo que estamos intentando es un ''cambio'' (en el lenguaje Array), pero devolviendo los caracteres restantes, en lugar de lo que se cambió. ¡Usemos nuestro Ruby para hacer esto posible con cuerdas! Podemos usar la operación del bracket rápido, pero darle un buen nombre, y tomar un arg para especificar cuánto queremos quitar del frente:
class String
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
end
Pero podemos hacer más con esa operación de soporte rápido pero poco manejable. Mientras estamos en ello, para completar, vamos a escribir un #shift
y #first
para String (¿por qué debería Array tener toda la diversión?), Tomando un arg para especificar cuántos caracteres queremos eliminar desde el principio:
class String
def first(how_many = 1)
self[0...how_many]
end
def shift(how_many = 1)
shifted = first(how_many)
self.replace self[how_many..-1]
shifted
end
alias_method :shift!, :shift
end
Ok, ahora tenemos una buena manera clara de sacar a los personajes del frente de una cadena, con un método que es consistente con Array#first
y Array#shift
(¿cuál debería ser realmente un método bang?). ¡Y también podemos obtener fácilmente la cadena modificada con #eat!
. Hm, ¿deberíamos compartir nuestro nuevo eat!
poder con Array? ¡Por qué no!
class Array
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
end
Ahora podemos:
> str = "[12,23,987,43" #=> "[12,23,987,43"
> str.eat! #=> "12,23,987,43"
> str #=> "12,23,987,43"
> str.eat!(3) #=> "23,987,43"
> str #=> "23,987,43"
> str.first(2) #=> "23"
> str #=> "23,987,43"
> str.shift!(3) #=> "23,"
> str #=> "987,43"
> arr = [1,2,3,4,5] #=> [1, 2, 3, 4, 5]
> arr.eat! #=> [2, 3, 4, 5]
> arr #=> [2, 3, 4, 5]
¡Eso es mejor!
Ejemplo:
[12,23,987,43
¿Cuál es la forma más rápida y más eficiente de eliminar el " [
", utilizando quizás un chop()
pero para el primer personaje?
A partir de Ruby 2.5, puede usar delete_prefix
o delete_prefix!
para lograr esto de una manera legible
En este caso, "[12,23,987,43".delete_prefix("[")
.
Más información aquí:
https://blog.jetbrains.com/ruby/2017/10/10-new-features-in-ruby-2-5/
https://bugs.ruby-lang.org/issues/12694
''invisible''.delete_prefix(''in'') #=> "visible"
''pink''.delete_prefix(''in'') #=> "pink"
Nota: también puede usar esto para eliminar elementos del final de una cadena con delete_suffix
y delete_suffix!
''worked''.delete_suffix(''ed'') #=> "work"
''medical''.delete_suffix(''ed'') #=> "medical"
https://bugs.ruby-lang.org/issues/13665
Editar:
Usando la configuración de referencia de Tin Man, parece bastante rápido también (en las dos últimas entradas delete_p
y delete_p!
). No acaba de pip los favoritos anteriores de velocidad, aunque es muy legible.
2.5.0
user system total real
[0] 0.174766 0.000489 0.175255 ( 0.180207)
[/^./] 0.318038 0.000510 0.318548 ( 0.323679)
[/^/[/] 0.372645 0.001134 0.373779 ( 0.379029)
sub+ 0.460295 0.001510 0.461805 ( 0.467279)
sub 0.498351 0.001534 0.499885 ( 0.505729)
gsub 1.669837 0.005141 1.674978 ( 1.682853)
[1..-1] 0.199840 0.000976 0.200816 ( 0.205889)
slice 0.279661 0.000859 0.280520 ( 0.285661)
length 0.268362 0.000310 0.268672 ( 0.273829)
eat! 0.341715 0.000524 0.342239 ( 0.347097)
reverse 0.335301 0.000588 0.335889 ( 0.340965)
delete_p 0.222297 0.000832 0.223129 ( 0.228455)
delete_p! 0.225798 0.000747 0.226545 ( 0.231745)
Alternativa ineficiente:
str.reverse.chop.reverse
Camino fácil:
str = "[12,23,987,43"
removed = str[1..str.length]
Manera impresionante:
class String
def reverse_chop()
self[1..self.length]
end
end
"[12,23,987,43".reverse_chop()
(Nota: prefiere la manera fácil :))
Encuentro una buena solución para ser str.delete(str[0])
para su legibilidad, aunque no puedo dar fe de su rendimiento.
Me gusta usar algo como:
asdf = "[12,23,987,43" asdf[0] = '''' p asdf # >> "12,23,987,43"
Siempre estoy buscando la manera más rápida y más fácil de hacer las cosas:
require ''benchmark''
N = 1_000_000
puts RUBY_VERSION
STR = "[12,23,987,43"
Benchmark.bm(7) do |b|
b.report(''[0]'') { N.times { "[12,23,987,43"[0] = '''' } }
b.report(''sub'') { N.times { "[12,23,987,43".sub(/^/[+/, "") } }
b.report(''gsub'') { N.times { "[12,23,987,43".gsub(/^/[/, "") } }
b.report(''[1..-1]'') { N.times { "[12,23,987,43"[1..-1] } }
b.report(''slice'') { N.times { "[12,23,987,43".slice!(0) } }
b.report(''length'') { N.times { "[12,23,987,43"[1..STR.length] } }
end
Corriendo en mi Mac Pro:
1.9.3
user system total real
[0] 0.840000 0.000000 0.840000 ( 0.847496)
sub 1.960000 0.010000 1.970000 ( 1.962767)
gsub 4.350000 0.020000 4.370000 ( 4.372801)
[1..-1] 0.710000 0.000000 0.710000 ( 0.713366)
slice 1.020000 0.000000 1.020000 ( 1.020336)
length 1.160000 0.000000 1.160000 ( 1.157882)
Actualizando para incorporar una respuesta más sugerida:
require ''benchmark''
N = 1_000_000
class String
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
def first(how_many = 1)
self[0...how_many]
end
def shift(how_many = 1)
shifted = first(how_many)
self.replace self[how_many..-1]
shifted
end
alias_method :shift!, :shift
end
class Array
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
end
puts RUBY_VERSION
STR = "[12,23,987,43"
Benchmark.bm(7) do |b|
b.report(''[0]'') { N.times { "[12,23,987,43"[0] = '''' } }
b.report(''sub'') { N.times { "[12,23,987,43".sub(/^/[+/, "") } }
b.report(''gsub'') { N.times { "[12,23,987,43".gsub(/^/[/, "") } }
b.report(''[1..-1]'') { N.times { "[12,23,987,43"[1..-1] } }
b.report(''slice'') { N.times { "[12,23,987,43".slice!(0) } }
b.report(''length'') { N.times { "[12,23,987,43"[1..STR.length] } }
b.report(''eat!'') { N.times { "[12,23,987,43".eat! } }
b.report(''reverse'') { N.times { "[12,23,987,43".reverse.chop.reverse } }
end
Lo que resulta en:
2.1.2
user system total real
[0] 0.300000 0.000000 0.300000 ( 0.295054)
sub 0.630000 0.000000 0.630000 ( 0.631870)
gsub 2.090000 0.000000 2.090000 ( 2.094368)
[1..-1] 0.230000 0.010000 0.240000 ( 0.232846)
slice 0.320000 0.000000 0.320000 ( 0.320714)
length 0.340000 0.000000 0.340000 ( 0.341918)
eat! 0.460000 0.000000 0.460000 ( 0.452724)
reverse 0.400000 0.000000 0.400000 ( 0.399465)
Y otra usando /^./
para encontrar el primer caracter:
require ''benchmark''
N = 1_000_000
class String
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
def first(how_many = 1)
self[0...how_many]
end
def shift(how_many = 1)
shifted = first(how_many)
self.replace self[how_many..-1]
shifted
end
alias_method :shift!, :shift
end
class Array
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
end
puts RUBY_VERSION
STR = "[12,23,987,43"
Benchmark.bm(7) do |b|
b.report(''[0]'') { N.times { "[12,23,987,43"[0] = '''' } }
b.report(''[/^./]'') { N.times { "[12,23,987,43"[/^./] = '''' } }
b.report(''[/^/[/]'') { N.times { "[12,23,987,43"[/^/[/] = '''' } }
b.report(''sub+'') { N.times { "[12,23,987,43".sub(/^/[+/, "") } }
b.report(''sub'') { N.times { "[12,23,987,43".sub(/^/[/, "") } }
b.report(''gsub'') { N.times { "[12,23,987,43".gsub(/^/[/, "") } }
b.report(''[1..-1]'') { N.times { "[12,23,987,43"[1..-1] } }
b.report(''slice'') { N.times { "[12,23,987,43".slice!(0) } }
b.report(''length'') { N.times { "[12,23,987,43"[1..STR.length] } }
b.report(''eat!'') { N.times { "[12,23,987,43".eat! } }
b.report(''reverse'') { N.times { "[12,23,987,43".reverse.chop.reverse } }
end
Lo que resulta en:
# >> 2.1.5
# >> user system total real
# >> [0] 0.270000 0.000000 0.270000 ( 0.270165)
# >> [/^./] 0.430000 0.000000 0.430000 ( 0.432417)
# >> [/^/[/] 0.460000 0.000000 0.460000 ( 0.458221)
# >> sub+ 0.590000 0.000000 0.590000 ( 0.590284)
# >> sub 0.590000 0.000000 0.590000 ( 0.596366)
# >> gsub 1.880000 0.010000 1.890000 ( 1.885892)
# >> [1..-1] 0.230000 0.000000 0.230000 ( 0.223045)
# >> slice 0.300000 0.000000 0.300000 ( 0.299175)
# >> length 0.320000 0.000000 0.320000 ( 0.325841)
# >> eat! 0.410000 0.000000 0.410000 ( 0.409306)
# >> reverse 0.390000 0.000000 0.390000 ( 0.393044)
Aquí hay otra actualización sobre hardware más rápido y una versión más nueva de Ruby:
2.3.1
user system total real
[0] 0.200000 0.000000 0.200000 ( 0.204307)
[/^./] 0.390000 0.000000 0.390000 ( 0.387527)
[/^/[/] 0.360000 0.000000 0.360000 ( 0.360400)
sub+ 0.490000 0.000000 0.490000 ( 0.492083)
sub 0.480000 0.000000 0.480000 ( 0.487862)
gsub 1.990000 0.000000 1.990000 ( 1.988716)
[1..-1] 0.180000 0.000000 0.180000 ( 0.181673)
slice 0.260000 0.000000 0.260000 ( 0.266371)
length 0.270000 0.000000 0.270000 ( 0.267651)
eat! 0.400000 0.010000 0.410000 ( 0.398093)
reverse 0.340000 0.000000 0.340000 ( 0.344077)
¿Por qué gsub es tan lento?
Después de hacer una búsqueda / reemplazo, gsub
tiene que verificar si hay coincidencias adicionales posibles antes de que pueda decir si está terminado. sub
solo hace uno y termina. Considere gsub
como si fuera un mínimo de dos llamadas sub
.
Además, es importante recordar que gsub
y sub
también pueden verse perjudicados por gsub
mal escritas que coinciden mucho más lentamente que una búsqueda de subcadena. Si es posible, ancle la expresión regular para obtener la mayor velocidad de la misma. Aquí hay respuestas en que demuestran que busque si desea más información.
Podemos usar slice para hacer esto:
val = "abc"
=> "abc"
val.slice!(0)
=> "a"
val
=> "bc"
Usando slice!
podemos eliminar cualquier caracter especificando su índice.
Por ejemplo: a = "One Two Three"
1.9.2-p290 > a = "One Two Three"
=> "One Two Three"
1.9.2-p290 > a = a[1..-1]
=> "ne Two Three"
1.9.2-p290 > a = a[1..-1]
=> "e Two Three"
1.9.2-p290 > a = a[1..-1]
=> " Two Three"
1.9.2-p290 > a = a[1..-1]
=> "Two Three"
1.9.2-p290 > a = a[1..-1]
=> "wo Three"
De esta forma, puede eliminar uno por uno el primer carácter de la cadena.
Si siempre quieres quitar los corchetes principales:
"[12,23,987,43".gsub(/^/[/, "")
Si solo desea eliminar el primer carácter, y sabe que no estará en un conjunto de caracteres multibyte:
"[12,23,987,43"[1..-1]
o
"[12,23,987,43".slice(1..-1)
Similar a la respuesta de Pablo anterior, pero un limpiador de tono:
str[1..-1]
Devolverá la matriz desde 1 hasta el último carácter.
''Hello World''[1..-1]
=> "ello World"
Usando regex:
str = ''string''
n = 1 #to remove first n characters
str[/.{#{str.size-n}}/z/] #=> "tring"
prefiero esto
srt = [12,23,987,43
p srt[1..-1]
>> 12,23,987,43
class String
def bye_felicia()
felicia = self.strip[0] #first char, not first space.
self.sub(felicia, '''')
end
end
str = "[12,23,987,43"
str[0] = ""