Rubyで文字列から数値を抽出する


82

私はこのコードを使用しています:

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

次のような文字列から数値を抽出するには:

ABCD1234
ABCD1235
ABCD1236

等

それは機能しますが、Rubyでこれに代わる他の方法は何ですか?

私のコード:

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

回答:


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

mapそれをどのように理解すべきかという意味は何ですか?私は理解してcollectいますが、地図を理解するのにいつも苦労していました。
— OscarRyz 2010

3
@Oscar Reyes、Enumerable#mapはEnumerable#collectの同義語です
— Wayne Conrad

3
参考:数字が他の文字で分割されている場合、これは数字の最初の「チャンク」のみを取得します。したがって、「123ABC456」の場合、「123」のみを取得します。すべての数値を取得する場合は、line.gsub(/ [^ 0-9] /、 '')のようなものを使用します。
— Joshua Pinter 2013

4
また、これは、タイトルが要求している文字列ではなく、配列などの列挙型で機能することを明確にする必要があります
— allenwlee 2015年

4
NoMethodError:未定義のメソッド文字列のための`マップ」
— ギャリー・ゴメス

177

http://www.ruby-forum.com/topic/125709によると多くのRubyの方法があります

  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/, '')

コンソールでそれぞれ試してください。

その投稿のベンチマークレポートも確認してください。


24
line.delete( "^ 0-9")は、リンクによると最速です
— Weston Ganger 2015

62

さらに簡単な解決策があります

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

これは、文字列から連続番号の最初の一致のみを返します。だから、'ab123cd45'.scan(/\d+/).firstちょうど戻ってくる12
— lacostenycoderを

5

最も簡単で最速の方法は、文字列からすべての整数を取得することです。

str = 'abc123def456'

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

長い文字列のベンチマークをここで提供されている他のソリューションのいくつかと比較すると、これは桁違いに高速であることがわかります。

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

これはうまくいくはずです。


投稿を編集して、コードの機能と問題が解決する理由についての説明を追加することを検討してください。ほとんどの場合、コードが含まれているだけの回答(機能している場合でも)は、通常、OPが問題を理解するのに役立ちません。
— SuperBiasedMan 2015

2

別の解決策は、次のように書くことです。

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.

今、あなたがタイプすると

myNumber = myString.to_i #or myString.to_f

これは


一般に、このような序数を使用することは、マルチバイト文字セットの時代の一般的な解決策として少し危険です。扱っている文字と文字セットに応じて、ロケールによって結果が異なる可能性があります。
— Brendon Whateley 2017

0

文字列から数値部分を抽出するには、次を使用します。

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

戻るはずです 1234


あなたがする必要はありませんmatchか、tryあなたは、この文字列マッチング構文を使用している場合str[/\d+/]
— lacostenycoder

また、.tryこの答えはなくて失敗したように、コアルビーではないactive_support/core_ext/object/try.rbか、レール
— lacostenycoder
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.