Trích xuất số từ chuỗi trong Ruby


82

Tôi đang sử dụng mã này:

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

Để trích xuất các số từ các chuỗi như:

ABCD1234
ABCD1235
ABCD1236

Vân vân.

Nó hoạt động, nhưng tôi tự hỏi tôi có thay thế nào khác cho điều này trong Ruby?

Mã của tôi:

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

Câu trả lời:


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

Tôi mapnên hiểu ngữ nghĩa của nó như thế nào? Tôi hiểu collectnhưng tôi luôn gặp khó khăn khi hiểu bản đồ.
OscarRyz

3
@ Oscar Reyes, Enumerable # bản đồ là một từ đồng nghĩa với Enumerable # thu thập
Wayne Conrad

3
FYI: Nếu bạn có các số được phân tách bởi các ký tự khác, điều này chỉ lấy "phần" đầu tiên của các số. Vì vậy, đối với '123ABC456', nó sẽ chỉ lấy '123'. Sử dụng một cái gì đó như line.gsub (/ [^ 0-9] /, '') nếu bạn muốn lấy tất cả các số.
Joshua Pinter,

4
Cũng cần làm rõ rằng công trình này trên một đếm được như một mảng, không phải là một chuỗi như tiêu đề được hỏi
allenwlee

4
NoMethodError: phương thức không xác định `` bản đồ '' cho Chuỗi
Garry Gomez

176

Có nhiều cách Ruby theo 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/, '')

Hãy thử từng thứ trên bảng điều khiển của bạn.

Cũng kiểm tra báo cáo điểm chuẩn trong bài đăng đó.


24
line.delete ("^ 0-9") là nhanh nhất theo liên kết
Weston Ganger

62

thậm chí còn có giải pháp đơn giản hơn

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

điều này chỉ trả về kết quả khớp đầu tiên của các số liên tiếp từ chuỗi. Vì vậy, 'ab123cd45'.scan(/\d+/).firstsẽ chỉ trở lại12
lacostenycoder

5

Cách đơn giản và nhanh nhất là lấy tất cả các số nguyên ra khỏi chuỗi.

str = 'abc123def456'

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

So sánh các điểm chuẩn trên một chuỗi dài với một số giải pháp khác được cung cấp ở đây, chúng ta có thể thấy đây là mức độ nhanh hơn:

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

Điều này sẽ hoạt động.


Vui lòng xem xét chỉnh sửa bài đăng của bạn để thêm giải thích về những gì mã của bạn làm và tại sao nó sẽ giải quyết vấn đề. Một câu trả lời chủ yếu chỉ chứa mã (ngay cả khi nó đang hoạt động) thường sẽ không giúp OP hiểu được vấn đề của họ.
SuperBiasedMan

2

Một giải pháp khác có thể là viết:

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.

Bây giờ, nếu bạn gõ

myNumber = myString.to_i #or myString.to_f

Điều này sẽ trả về một


Nói chung, sử dụng thứ tự như thế này là một chút nguy hiểm như một giải pháp chung trong thời đại của các bộ ký tự nhiều byte. Tùy thuộc vào các ký tự bạn đang xử lý và bộ ký tự, mọi thứ có thể nhận được các kết quả khác nhau ở các ngôn ngữ khác nhau.
Brendon Whateley

0

Để trích xuất phần số từ một chuỗi, hãy sử dụng như sau:

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

Nó sẽ trở lại 1234


Bạn không cần matchhoặc trynếu bạn sử dụng cú pháp đối sánh chuỗi nàystr[/\d+/]
lacostenycoder

cũng .trykhông phải là ruby lõi nên câu trả lời này không thành công mà không active_support/core_ext/object/try.rbhoặc đường ray
lacostenycoder
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.