有没有一个在Ruby中能够规范和格式化美国电话号码的宝石?

14

我曾使用Phony格式化电话号码(意思是,如果我输入了xxx-xxx-xxxx,它会将其转换为字符串,并告诉我是否有(1)在前面需要去掉)。

但它对我们的电话号码实际上并不起作用,它是为国际号码设计的。

是否存在相应的替代方案?

谢谢。

http://rubygems.org/gems/phony


在String类中编写一个方法是不可能的吗? - Kyle Macey
我该怎么做?--它能添加到库文件中吗? - Satchel
是的,作为String.rb类,只需定义String类,然后您的方法“def convert_to_phone_number”即可。 - Kyle Macey
@kyle -- 嗯,实际上通过逻辑的方法会是什么呢...有时候值是xxx-xxxx-xxxx,但我可能想要将其规范化为xxxxxxxx。 - Satchel
但是当我想要显示时,我希望它以xxx-xxx-xxxx的形式呈现...这有意义吗? - Satchel
6个回答

21
今年早些时候,我审查了一堆解析和格式化电话号码的 Ruby 宝石。它们分为几类(见下文)。简而言之,我使用了“phone”。如果你的电话号码不包括国家代码,它可能适合你,因为你可以指定一个默认的国家代码。
1)以美国为中心: big-phoney (0.1.4) phone_wrangler (0.1.3) simple_phone_number (0.1.9)
2)依赖于rails或active_record: phone_number (1.2.0) validates_and_formats_phones (0.0.7)
3)'phone' 的分支已经合并回主干: elskwid-phone (0.9.9.4) tfe-phone (0.9.9.1)
4)需要你提前知道地区信息: phoney (0.1.0)
5)对我来说有点可行: phone (0.9.9.3)
6)宝石名称中不包含'substring 'phone''(注:我看到您尝试过这个)
这些分组可能有些不公平或过时,请自由发表评论。我必须承认,当时有多少人在部分重新创造这个特定的轮子让我有点沮丧。

“phone” gem 看起来有点不活跃 - 有几个拉取请求没有得到回应。我使用了这个分支:https://github.com/g1smd/carrphone,因为我需要正确的英国电话号码。 - Dominic Sayers
根据要探索的选项更新了此内容。 - Satchel

13

我从未见过一种可靠的电话号码格式化工具,因为这太难了,很难做到完美。就在你认为已经掌握了所有情况时,又会出现新的需要格式化的电话号码。

十位北美电话号码可能是最容易格式化的,你可以使用正则表达式,但一旦遇到分机号,就会遇到麻烦。不过,如果你想自己动手,还是有办法解决的:

def formatted_number(number)
  digits = number.gsub(/\D/, '').split(//)

  if (digits.length == 11 and digits[0] == '1')
    # Strip leading 1
    digits.shift
  end

  if (digits.length == 10)
    # Rejoin for latest Ruby, remove next line if old Ruby
    digits = digits.join
    '(%s) %s-%s' % [ digits[0,3], digits[3,3], digits[6,4] ]
  end
end

这段代码将会把11位和10位数字转换成你想要的格式。

以下是一些示例:

formatted_number("1 (703) 451-5115")
 # => "(703) 451-5115"
formatted_number("555-555-1212")
 # => "(555) 555-1212"

如果输入的是4155551212会发生什么? - Satchel
当然,你可以自己尝试并发现!只要有11或10个数字存在,非数字字符将被忽略,它将以相同的方式进行格式化。 - tadman
哦...非数字字符被忽略了...我想我需要学习更多关于正则表达式的知识以及你是如何使用它的,这就是为什么我遇到问题的原因...我猜 \D 是用来匹配非数字字符的? - Satchel
\s 表示空格,\S 表示非空格,因此几个事物的大写版本是相反的。请参考 Rubular 获取更多示例和帮助工具。 - tadman
4
在我的 Ruby 1.9.3 版本中,我需要在这行代码 '(%s) %s-%s' % [ digits[0,3], digits[3,3], digits[6,4] ] 前插入 digits = digits.join - jwal
显示剩余5条评论

3

我写了这个正则表达式来匹配NANPA电话号码,并在几个月前将其转换为Rails验证器用于项目中。它对我来说很好用,但更实际而非严格符合规范。

# app/validators/phone_number_validator.rb
class PhoneNumberValidator < ActiveModel::EachValidator
  @@regex = %r{\A(?:1(?:[. -])?)?(?:\((?=\d{3}\)))?([2-9]\d{2})(?:(?<=\(\d{3})\))? ?(?:(?<=\d{3})[.-])?([2-9]\d{2})[. -]?(\d{4})(?: (?:ext|x)\.? ?(\d{1,5}))?\Z}

  def validate_each (object, attribute, value)
    if m = value.match(@@regex)
      # format the phone number consistently
      object.send("#{attribute}=", "(#{m[1]}) #{m[2]}-#{m[3]}")
    else
      object.errors[attribute] << (options[:message] || "is not an appropriately formatted phone number")
    end
  end
end

# app/models/foobar.rb
class Foobar < ActiveRecord::Base
  validates :phone, phone_number: true
end

保存/输出的格式如下:(888) 888-8888。目前的输出会去掉分机号,因为我不需要它。你可以很容易地添加它并更改格式(请参阅object.send行)。

1
#RAILS_ROOT/lib/String.rb
class String
  def convert_to_phone
    number = self.gsub(/\D/, '').split(//)

    #US 11-digit numbers
    number = number.drop(1) if (number.count == 11 && number[0] == 1)

    #US 10-digit numbers
    number.to_s if (number.count == 10)

  end


  def format_phone
    return "#{self[0,3]}-#{self[3,3]}-#{self[6,4]}"
  end
end

"585-343-2070".convert_to_phone 
=> "5853432070"

"5853432070".convert_to_phone
=> "5853432070"

"1(585)343-2070".convert_to_phone.format_phone
=> "585-343-2070"

##Everything formatted as requested in Asker's various comments

@kyle 我明白了,所以这将用于规范化到数据库...然后我会使用另一个响应来显示它(以漂亮的方式显示为xxx-xxx-xxxx>)。 - Satchel
虽然不是很DRY,但我稍后会更新更好的内容。 - Kyle Macey
我明白了,谢谢。有没有更好的方法?我在想应该把它们都以相同的方式存储在数据库中,然后允许我进行格式化。我认为这样可行,让我试试,谢谢。 - Satchel
这是我收到的控制台错误信息:irb(main):001:0> "585-343-2070".convert_to_phone NoMethodError: undefined method `convert_to_phone' for "585-343-2070":String from (irb):1 - Satchel
啊,好的,我把它移到初始化器里了。它有点起作用了。这会给e一个nil,这不应该是这样的:"1(585)343-2070".convert_to_phone - Satchel
显示剩余6条评论

0

0
def format_phone_numbers(n)
    "(#{n[-10..-8]}) #{n[-7..-5]}-#{n[-4..-1]}"
end

format_phone_numbers('555555555555')

"(555) 555-5555"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接