Ruby中的正则表达式:检查总位数

时间:2012-06-21 11:45:11

标签: ruby regex

我需要一行gsub来替换字符串中的所有非数字,但仅当非数字不超过3且数字总长度为10时才需要

我有这个符合第一个条件

p "0177/385490".gsub(/((\d+)\D?(\d+)\D?(\d+)\D?+(\d+))/,'\2\3\4\5') 
#=>"0177385490"

但是当我尝试这个时,{10}检查不起作用

p "0177/385490".gsub(/((\d+)\D?(\d+)\D?(\d+)\D?+(\d+)){10}/,'\2\3\4\5') 
#=>"0177/385490"

请问怎么做?

修改

我设法就这样了,但是如何在oneline gsub上做到这一点?

strings = [
   "0473/385 490",
   "0473/385490",
   "0473 38 54 90",
   "0473/385 4901"    #this one is't captured
 ]

 strings.each do |s|
   if /((\d+)\D?(\d+)\D?(\d+)\D?+(\d+))/ =~ s
     if "#{$2}#{$3}#{$4}#{$5}".length == 10
       puts "#{$2}#{$3}#{$4}#{$5}"
     end
   end
 end

编辑:为了说明为什么它真的需要成为一个onle line gsub在这里,我的例程,将会有更多的替换添加

def cleanup text
  replacements = [
     {:pattern => /(04\d{2}) (\d{2}) (\d{2}) (\d{2})/, :replace_with => '\1\2\3\4'},
     {:pattern => /(0\d)(\/| |-)(\d{3}) (\d{2}) (\d{2})/, :replace_with => '\1\3\4\5'},
     {:pattern => /(\d{6} )(\d{3})-(\d{2})/, :replace_with => '\1\2 \3'},
     {:pattern => /(\d{2,4})\D?(\d{2,3})\D?(\d{2,3})/, :replace_with => '\1\2\3'}
  ].each{|replacement|text.gsub!(replacement[:pattern], replacement[:replace_with])}
  text
end

5 个答案:

答案 0 :(得分:3)

我认为单行gsub不会过于可读。这是我的方法:

chars, non_chars = s.each_char.partition { |c| c =~ /\d/ }
puts chars.join if chars.size == 10 && non_chars.size <= 3

清洁易读,没有任何魔法变量。此外,它清楚地显示了您对字符串施加的规则。

答案 1 :(得分:3)

这是一个带有gsub的单线程,主要是为了说明为什么迈克尔科尔的方法更好:

(digits = s.gsub(/\D/, '')).length == 10 && s.length < 14 ? digits : s

答案 2 :(得分:1)

您可以使用以下内容:

puts s.gsub(/\D/, '') if (/\A(\d\D?){10}\z/ =~ s) && (/\A(\d+\D){0,3}\d*\z/ =~ s)

答案 3 :(得分:1)

您可能还想了解scan方法。

strings.each do |s|
  numbers = s.scan(/\d/).join
  non_numbers = s.scan(/\D/)
  puts numbers if numbers.length == 10 && non_numbers.length < 4
end

但我更喜欢@MichaelKohl的解决方案。

然后是一个愚蠢的例子:

strings.select{|s| s.scan(/\D/).length < 4}.map{|s| s.scan(/\d/).join}.select{|s| s.length==10}

答案 4 :(得分:0)

谢谢大家,但我无法使用答案,因为我无法将它们插入我的日常工作中(编辑我的答案以使其更清晰)。我自己找到了溶剂。我给每个人一个按要求提供单行解决方案的upvote,现在我仍然需要找到一种方法在清理例程中插入我的块作为替换模式

p "0177/3854901".gsub(/(\d+)\D?(\d+)\D?(\d+)\D?+(\d+)/){ |m| "#{$1}#{$2}#{$3}#{$4}".length==10 ? "#{$1}#{$2}#{$3}#{$4}":m} 
#=> "0177/3854901" isn't replaced because it has 11 digits
p "0177/385490".gsub(/(\d+)\D?(\d+)\D?(\d+)\D?+(\d+)/){ |m| "#{$1}#{$2}#{$3}#{$4}".length==10 ? "#{$1}#{$2}#{$3}#{$4}":m} 
#=> "0177385490"