`String#sub`方法在第一次执行时返回不正确的值

时间:2012-11-20 15:29:34

标签: ruby

我试图通过在子字符串的每个部分中插入连字符来使UUID成为正确符合的UUID。

test = "CB13DBB20A9945CC86F11914C979C761"
#The first one will return '----' so essentially the $1 to $5 are returned as emptys
test.sub(/(\h{8})(\h{4})(\h{4})(\h{4})(\h{12})/, "#{$1}-#{$2}-#{$3}-#{$4}-#{$5}")
#Returns the ideal result of CB13DBB2-0A99-45CC-86F1-1914C979C761
test.sub(/(\h{8})(\h{4})(\h{4})(\h{4})(\h{12})/, "#{$1}-#{$2}-#{$3}-#{$4}-#{$5}")

正如您所看到的,第一次运行该函数不起作用,但第二次运行。任何想法都会很棒。作为附加信息,

test.match(/(\h{8})(\h{4})(\h{4})(\h{4})(\h{12})/){|m| "#{$1}-#{$2}-#{$3}-#{$4}-#{$5}"}

将首次使用。单引号和双引号不会影响任何内容。

4 个答案:

答案 0 :(得分:4)

虽然这可以使用正则表达式完成,但我会选择子字符串:

require 'pp'

uuid = 'CB13DBB20A9945CC86F11914C979C761'
pp [uuid[0, 8], uuid[8, 4], uuid[12, 4], uuid[16, 4], uuid[20, 12]]
# => ["CB13DBB2", "0A99", "45CC", "86F1", "1914C979C761"]

puts [
  uuid[0, 8], uuid[8, 4], uuid[12, 4], uuid[16, 4], uuid[20, 12]
].join('-')
# => CB13DBB2-0A99-45CC-86F1-1914C979C761

因为在编写代码时使用偏移量和长度可能是一件苦差事,所以这里是使用unpack只有长度的替代品:

lengths = [8, 4, 4, 4, 12]
uuid.unpack(lengths.map{ |l| "a#{ l }" }.join).join('-')
# => "CB13DBB2-0A99-45CC-86F1-1914C979C761"

答案 1 :(得分:3)

像这样引用模式匹配。

test.sub(/(\h{8})(\h{4})(\h{4})(\h{4})(\h{12})/, '\1-\2-\3-\4-\5')

您在Ruby Docs中解释了这种行为的原因:

  

如果replacement是一个String,它将替换匹配的文本。 它可能包含对格式\ d的模式捕获组的反向引用,其中d是组号,或\ k,其中n是组名。如果它是双引号字符串,则两个反向引用都必须以额外的反斜杠开头。 但是,在替换中,特殊匹配变量(例如& $)不会引用当前匹配

答案 2 :(得分:1)

在您的示例中,$ 1 ... $ 5替换为字符串替换之前。

如果您想在替换期间对它们进行评估,请改为使用块形式:

test.sub(/(\h{8})(\h{4})(\h{4})(\h{4})(\h{12})/) { "#{$1}-#{$2}-#{$3}-#{$4}-#{$5}" }

答案 3 :(得分:0)

FWIW,Ruby有SecureRandom来提供uuid的

require 'securerandom'
p SecureRandom.uuid #"dd1f58f8-8c42-47e0-9c08-a8d5c191c9c3"

使用String#unpack

可以轻松地将字符串分片
test = "CB13DBB20A9945CC86F11914C979C761"
p test.unpack("A8A4A4A4A8").join('-') #"CB13DBB2-0A99-45CC-86F1-1914C979"