Ruby, remove os últimos N caracteres de uma string?

263

Qual é a maneira preferida de remover os últimos ncaracteres de uma string?

JP Silvashy
fonte
Se você conhece o sufixo (a resposta principal sugere que muitas pessoas procurem aqui), você pode usar o delete_suffixRuby 2.5. Mais informações aqui .
SRack

Respostas:

36

Ruby 2.5+

A partir do Ruby 2.5, você pode usar delete_suffixou delete_suffix!conseguir isso de maneira rápida e legível.

Os documentos sobre os métodos estão aqui .

Se você sabe qual é o sufixo, isso é idiomático (e eu diria, ainda mais legível do que outras respostas aqui):

'abc123'.delete_suffix('123')     # => "abc"
'abc123'.delete_suffix!('123')    # => "abc"

É ainda mais rápido (quase 40% com o método bang) do que a resposta principal. Aqui está o resultado da mesma referência:

                     user     system      total        real
chomp            0.949823   0.001025   0.950848 (  0.951941)
range            1.874237   0.001472   1.875709 (  1.876820)
delete_suffix    0.721699   0.000945   0.722644 (  0.723410)
delete_suffix!   0.650042   0.000714   0.650756 (  0.651332)

Espero que isso seja útil - observe que o método atualmente não aceita uma regex, portanto, se você não souber o sufixo, não será viável no momento. No entanto, como a resposta aceita ( atualização: no momento da redação ) dita o mesmo, achei que isso poderia ser útil para algumas pessoas.

SRack
fonte
1
@JPSilvashy Nunca fiquei tão satisfeito em perder uma marca de seleção. Esta é uma ótima resposta.
Wayne Conrad
1
Este é um grande e rápido função, mas esta não é a resposta certa porque ele não responder à pergunta que é exatamenteWhat is the preferred way of removing the last n characters from a string?
Sam
1
Obrigado pelo feedback @Sam - essa pergunta teve uma resposta por quase nove anos que funcionou da mesma forma que esta, com 261 votos positivos no momento da redação deste artigo. O JP aceitou isso e recentemente mudou para isso, então eu diria que respondeu à pergunta deles :) Pensei em colocar isso como uma alternativa moderna e espero que ajude as pessoas que chegam aqui. De fato, eu cobri tudo isso na questão - espero que esse método aceite uma regex em breve, embora exista uma alternativa perfeita para o seu caso logo abaixo disso.
SRack 02/09/19
316
irb> 'now is the time'[0...-4]
=> "now is the "
DigitalRoss
fonte
9
Observe que isso funciona apenas no Ruby 1.9. No Ruby 1.8, isso removerá os últimos bytes , não os últimos caracteres .
Jörg W Mittag
2
Mas ele provavelmente quis dizer "bytes" se ele estiver usando o 1.8.x.
DigitalRoss
4
Isso funciona, mas estou achando 'abc123'.chomp (' 123 ') duas vezes mais rápido para seqüências curtas e muito longas. (Ruby 2.0.0-p247) Alguém pode confirmar isso?
Plasmarob
10
Para aqueles que querem saber por que este exemplo específico não work..there são 3 pontos não 2 ou seja, [0...-4]não[0..-4]
rorofromfrance
2
@Plamarob Acho que é mais relevante dizer que o chomp é 53 nanossegundos mais rápido do que dizer que é duas vezes mais rápido. Em seguida, você pode estimar melhor o custo versus o valor de usá-lo e se pode otimizar em uma determinada situação.
cesoid
266

Se os caracteres que você deseja remover são sempre os mesmos, considere chomp:

'abc123'.chomp('123')    # => "abc"

As vantagens de chompsão: sem contagem, e o código comunica mais claramente o que está fazendo.

Sem argumentos, chompremove a finalização da linha DOS ou Unix, se uma estiver presente:

"abc\n".chomp      # => "abc"
"abc\r\n".chomp    # => "abc"

A partir dos comentários, houve uma questão de velocidade de uso #chompversus uso de um intervalo. Aqui está uma referência comparando os dois:

require 'benchmark'

S = 'asdfghjkl'
SL = S.length
T = 10_000
A = 1_000.times.map { |n| "#{n}#{S}" }

GC.disable

Benchmark.bmbm do |x|
  x.report('chomp') { T.times { A.each { |s| s.chomp(S) } } }
  x.report('range') { T.times { A.each { |s| s[0...-SL] } } }
end

Resultados de benchmark (usando o CRuby 2.13p242):

Rehearsal -----------------------------------------
chomp   1.540000   0.040000   1.580000 (  1.587908)
range   1.810000   0.200000   2.010000 (  2.011846)
-------------------------------- total: 3.590000sec

            user     system      total        real
chomp   1.550000   0.070000   1.620000 (  1.610362)
range   1.970000   0.170000   2.140000 (  2.146682)

Portanto, o chomp é mais rápido do que usar um intervalo, em ~ 22%.

Wayne Conrad
fonte
5
Chop também é uma opção. É menos exigente com o que é removido.
Andrew Grimm
1
Eu descobri que o oposto é realmente verdadeiro. A realidade é que .chomp parece ser duas vezes mais rápido.
Plasmarob
3
@Plamarob, Benchmarks em Ruby costumam surpreender. Estou tão errado que não tento mais adivinhar o que será mais rápido. Além disso, se a resposta for aprimorada pelos resultados da referência, fique à vontade para editá-la.
Wayne Conrad
1
Se estou lendo o código corretamente, o intervalo leva cerca de 53 nanossegundos a mais que o chomp. Pode ser um empecilho significativo em determinadas situações, mas manter a velocidade absoluta em mente (e não apenas o parente) pode dizer se você deve percorrer sua base de código e alterar todos os seus intervalos em chomps (onde aplicável). Provavelmente não.
Cesoid 9/16
1
Funciona bem. E você pode usar chomp!()para atuar no String no local.
Joshua Pinter
57
str = str[0...-n]
Nakilon
fonte
5
Observe que isso funciona apenas no Ruby 1.9. No Ruby 1.8, isso removerá os últimos bytes , não os últimos caracteres .
Jörg W Mittag
5
Isso é melhor que a resposta escolhida, já que 3 pontos (...) são mais fáceis de memorizar, pois -n significa remover n caracteres do final da sequência.
Lulalala 3/11
também "abcd" [0 ..- 2] # => "abc" enquanto "abcd" [0 ...- 2] # => "ab". Na minha opinião, a opção de intervalo de 3 pontos resulta em um código mais auto-explicativo.
Mokagio 29/07
31

Eu sugeriria chop. Eu acho que foi mencionado em um dos comentários, mas sem links ou explicações, então aqui está o porquê de eu achar melhor:

Ele simplesmente remove o último caractere de uma string e você não precisa especificar nenhum valor para que isso aconteça.

Se você precisar remover mais de um personagem, então chompé sua melhor aposta. Isto é o que os documentos ruby têm a dizer sobre chop:

Retorna uma nova String com o último caractere removido. Se a sequência terminar com \ r \ n, os dois caracteres serão removidos. A aplicação de chop em uma string vazia retorna uma string vazia. String # chomp é geralmente uma alternativa mais segura, pois mantém a string inalterada se não terminar em um separador de registros.

Embora isso seja usado principalmente para remover separadores, como \r\neu usei para remover o último caractere de uma sequência simples, por exemplo, spara tornar a palavra singular.

kakubei
fonte
1
Isso não removeria apenas esse último caractere? A pergunta é sobre "personagens" em plural
maetthew
1
Sim, você está certo, mas o chomp ('chars') removerá os últimos 'chars'. Não estava claro para mim se o OP queria caracteres específicos ou apenas N caracteres.
kakubei
Sim, esta é a resposta, somente quando você deseja remover apenas um caractere (o que aconteceu comigo).
QUV
29
name = "my text"
x.times do name.chop! end

Aqui no console:

>name = "Nabucodonosor"
 => "Nabucodonosor" 
> 7.times do name.chop! end
 => 7 
> name
 => "Nabuco" 
joscas
fonte
Isso é eficiente? Parece um vale a pena uma comparação de referência para outras respostas :)
SRack
16

Soltando o último n caracteres é o mesmo que manter os primeiros length - ncaracteres.

O Suporte ativo inclui String#firste String#lastmétodos que fornecem uma maneira conveniente de manter ou eliminar o primeiro / último ncaracteres:

require 'active_support/core_ext/string/access'

"foobarbaz".first(3)  # => "foo"
"foobarbaz".first(-3) # => "foobar"
"foobarbaz".last(3)   # => "baz"
"foobarbaz".last(-3)  # => "barbaz"
chocolateboy
fonte
7

se você estiver usando trilhos, tente:

"my_string".last(2) # => "ng"

[EDITADO]

Para obter a string SEM os últimos 2 caracteres:

n = "my_string".size
"my_string"[0..n-3] # => "my_stri"

Nota: a última string char é n-1. Portanto, para remover os dois últimos, usamos o n-3.

Guihen
fonte
2
Isso não remove as duas últimas letras. Devolve-os.
JP Silvashy 11/04/2015
1
Você não precisa para medir a corda primeiro, rubi utiliza índices negativos a partir do final da cadeia nativamente
Devon Parsons
3

Você sempre pode usar algo como

 "string".sub!(/.{X}$/,'')

Onde X está o número de caracteres a serem removidos.

Ou com a atribuição / uso do resultado:

myvar = "string"[0..-X]

onde Xé o número de caracteres mais um para remover.

Zsolt Botykai
fonte
1

Se você concorda com a criação de métodos de classe e deseja os caracteres cortados, tente o seguinte:

class String
  def chop_multiple(amount)
    amount.times.inject([self, '']){ |(s, r)| [s.chop, r.prepend(s[-1])] }
  end
end

hello, world = "hello world".chop_multiple 5
hello #=> 'hello '
world #=> 'world'
Ben Aubin
fonte
0

Usando regex:

str = 'string'
n = 2  #to remove last n characters

str[/\A.{#{str.size-n}}/] #=> "stri"
Sagar Pandya
fonte
0

Se os caracteres que você deseja remover são sempre os mesmos, considere chomp:

'abc123'. chomp ('123')

Poonkodi
fonte
-3
x = "my_test"
last_char = x.split('').last
Reshmi Mitra
fonte
3
pergunta era sobre a remoção últimos N caracteres de uma string, não se trata de encontrar o último caractere
unnitallman