“字符串#sub”方法在第一次执行时返回不正确的值



我试图通过在子字符串的每个部分中插入一个连字符,将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}"}

将在第一次工作。单引号和双引号不会影响任何事情。

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

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"

像这样引用模式匹配。

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

您看到此行为的原因在 Ruby 文档中进行了解释:

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

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

如果要在替换期间对其进行评估,请改用块形式:

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

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"

最新更新