11

我想将邮政编码规范化为 5 位数长,用零替换任何缺失的字符,如下所示:

"95616" >> "95616"
"854"  >> "00854"
"062" >> "00062"
"0016" >> "00016"

我试过像这样sprintf("%05s", zipcode)和那样 使用 sprintf sprintf("%0.5d", zipcode)。两者都给出了错误的答案。使用s

"95616" >> "95616"
"854"   >> "  854"
"062"   >> "  062"
"0016"  >> " 0016"

这是正确的字符数,但使用空格,而不是零。

使用d

"95616" >> "95616"
"854"   >> "00854"
"062"   >> "00050"
"0016"  >> "00014"

在这种情况下, sprintf() 的正确用途是什么?

4

6 回答 6

27

不要折磨自己sprintf

puts "123".rjust(5, '0') # => 00123
于 2012-12-28T23:51:35.610 回答
8

您对 sprintf 的使用很好。您的问题是 062(和 0016)是八进制的(任何以 0 开头的整数也是如此),并且在转换为 base10 时变为 50。

解决方案是在 0 到达您的 Ruby 应用程序之前摆脱它。假设它是一个字符串(因为您的示例显示字符串),您可以执行以下操作:

"062".gsub /^0/, ''

然后继续填充和打印格式。

另一种方法是如果您知道它以 0 开头,则故意将其打印为八进制:

"%05o" % 062 # => "00062"

当然,如果您可以控制输入,最好的办法是确保人们不会通过输入您不期望的数字来破坏您的代码。例如。

"%05s" % 0xff0055 # => 16711765
"%05x" % 0xff0055 # => "ff0055"

检查输入将问题从格式化问题变为验证问题,预防胜于治疗。

(古怪的 % 语法是printf/的糖sprintf

于 2012-12-28T23:58:56.463 回答
6

你想要 %05d。也 String#% 作为快捷方式:

"%05d" % "123" #=> 00123
于 2012-12-29T00:05:08.370 回答
2

whirlwin 的解决方案在我看来是一个有效的(一般填充)解决方案。只需使用 max 改进它:

zipcode.insert 0, '0' * ([5 - zipcode.length, 0].max)

要检查它:

az = ["95616", "854", "062", "0016", '1', '123456']
az.collect {|zipcode| zipcode.insert 0, '0' * (5 - zipcode.length) }

$ ruby -w t.rb
t.rb:2:in `*': negative argument (ArgumentError)

添加 max 以应对负值:

az = ["95616", "854", "062", "0016", '1', '123456']
az.collect {|zipcode| zipcode.insert 0, '0' * ([5 - zipcode.length, 0].max) }
p az

$ ruby -w t.rb
["95616", "00854", "00062", "00016", "00001", "123456"]
于 2012-12-29T09:58:58.683 回答
0

虽然这种方法实际上不使用sprintf,但它应该在 1 行代码中解决您的问题:

zipcode.insert 0, '0' * (5 - zipcode.length)
于 2012-12-28T23:51:29.077 回答
0

谢谢大家的意见。我希望了解更多关于 sprintf 的信息,特别是在解决方案中使用 sprintf,所有的想法都非常有帮助。我最终想出了一个针对我的问题的 hacky 解决方案,它似乎很灵活而且还没有被提及,所以我想我会发布它。

正如我所提到的,sprintf("%05s", zipcode)如果数字字符串不够长,将返回空格而不是零,但它确实返回了正确数量的空格 - 所以我只是将 a 链接gsub到末尾以用零替换空格。

sprintf("%05s", zipcode).gsub!(" ", "0")

如果此解决方案有任何重大问题,请告诉我。我已经对其进行了测试,到目前为止它似乎有效。

于 2012-12-29T10:05:56.120 回答