如何在Ruby中输出前导零?

267

我正在使用Ruby脚本输出一组带编号的文件。编号来自于递增计数器,但为了使它们在目录中排序得好看些,我想在文件名中使用前导零。也就是说

file_001...

而不是

file_1

是否有简单的方法将数字转换为字符串时添加前导零?(我知道可以通过“if less than 10.... if less than 100”来实现)。

6个回答

376

使用字符串和%运算符:

irb(main):001:0> "%03d" % 5
=> "005"
左侧是一个printf格式字符串,右侧可以是一系列的值,因此你可以这样做:
irb(main):002:0> filename = "%s/%s.%04d.txt" % ["dirname", "filename", 23]
=> "dirname/filename.0023.txt"

这是一个printf格式字符串速查表,您可能会在编写格式字符串时找到它很有用。Printf格式最初来自于C函数printf,但类似的格式化函数也可在Perl、Ruby、Python、Java、PHP等语言中使用。


1
太好了!所以"%s"的意思是“在此处替换第N个值”,而“%03d”的意思是“在此处替换一个数字,添加尽可能多的零以使其成为一个三位数?”(我猜d代表“数字”)。我现在看到了这方面的文档(http://www.ruby-doc.org/core/classes/String.html#M000770),但它非常简洁,我想要一些详细说明。 - Nathan Long
1
我添加了一个 printf 格式的备忘单链接。其中 "s" 表示 "字符串","d" 表示 "十进制数"。而 "03" 则表示 "用零填充至 3 个字符"; "%3d" 则会在左侧用空格填充。 - Daniel Martin
2
顺便提一下 - 这与调用 Kernel#sprintf 相同,其文档在此处:http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-sprintf - Nathan Long
补充@NathanLong的评论,这个答案中的第一个示例将被写成sprintf("%03d", 5) - Dennis
这应该是被选中的答案。 - Dan Barron

308
如果计数器中的最大数字位数已知(例如对于1..876的计数器,n = 3),你可以执行:
str = "file_" + i.to_s.rjust(n, "0")

9
呵呵,这不算是最好的答案,但我多年来一直在使用 Ruby ,却不知道 rjust。干杯! - pauliephonic
必须点赞,因为似乎 %03s 由于某种奇怪的原因使用空格进行填充(%03d 看起来正常工作)。我本来以为在这两种情况下 C 都会使用零进行填充。 - Nerdmaster
1
最终将其切换为已接受的答案,因为它是最简单和最容易记住的。% 能够实现相同的功能,但是更加通用。 - Nathan Long
1
意外但最简单 - akostadinov
1
来这里是为了了解如何填充一个36进制数。这个方法可以实现,而%看起来不行。谢谢! - Soron
@Nerdmaster:就我个人而言,对我来说,%03s实际上会导致编译器错误:error: '0' flag used with ‘%s’ gnu_printf format [-Werror=format=]... 所以,不管你是否发誓,要么你弄错了,要么它已经改变了,要么... 至少有一个现代编译器不同意。 :) - undefined

54

在拼接文件名之前,你不能只使用值的字符串格式化吗?

"%03d" % number

我认为这个答案并没有为@Daniel Martin的答案增添任何内容,但我喜欢它的简洁性... - svelandiag
4
他和丹尼尔·马丁几乎同时回答,因此可能没有意识到重复。 - Kurt Peek
这非常适合于utc_offset。 - Abel

35

使用String#next作为计数器。

>> n = "000"
>> 3.times { puts "file_#{n.next!}" }
file_001
file_002
file_003

next 相对来说是比较“聪明”的,意味着你甚至可以继续使用它

>> n = "file_000"
>> 3.times { puts n.next! }
file_001
file_002
file_003

谢谢您指出这一点。这是一个非常棒的方法。 - Weston Ganger

31

如其他答案所述,"%03d" % number 的确可以很好地工作,但它违反了 rubocop Ruby 风格指南

  

更喜欢使用 sprintf 及其别名 format,而不是相当难懂的 String#% 方法。

我们可以使用以下方法以更可读的方式获得相同的结果:

format('%03d', number)

1
如果你的目标是学习一些鲜为人知的Ruby语言特性,那么可以使用别名format。但是如果你的目标是让代码易于理解,应该使用sprintf,因为它是C标准库的一部分,并且跨多种编程语言使用。了解sprintf的人比知道format是其别名的人要多得多。仅仅因为某个规则是RuboCop的一部分并不意味着它本质上是对还是错。选择最适合你项目的规则。而'%03d' % number更容易阅读。 - Tilo
3
我也曾遇到同样的问题,将"%02d" % num改为sprintf(...),然后按照RuboCop的建议再改为format(...)。之后我决定使用sprintfformat更传统,所以在rubocop.yml中更新了Style/FormatString: EnforcedStyle: sprintf,现在晚上我能睡个好觉了。 - David Hempy
7
RuboCop的默认配置实现了Ruby社区的风格指南(https://github.com/rubocop-hq/ruby-style-guide)。我不同意RuboCop是“一个晦涩的Ruby语言特性”的观点。如果更好的可读性对于您的项目很重要,那么定制cop配置是一个很好的主意;它被构建为适应个人需求,而Ruby反对“唯一正确的方法”思维方式!但是,遵循社区风格指南肯定是符合Ruby的惯用法的。 - David Bodow

3

filenames = '000'.upto('100').map { |index| "file_#{index}" }

输出结果

[file_000, file_001, file_002, file_003, ..., file_098, file_099, file_100]


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