我有以下十六进制字符串:"\xfe\xff"
. 我想将其转换为"feff"
. 我该怎么做呢?
我得到的最接近的是"\xfe\xff".inspect.gsub("\\x", "")
,它返回"\"FEFF\""
。
"\xfe\xff".unpack("H*").first
# => "feff"
您正在处理双引号字符串中的转义序列。双引号字符串中最常见的转义序列是“\n”,但 ruby 也允许您在字符串中使用其他转义序列。您的字符串 "\xfe\xff" 包含两个十六进制转义序列,格式如下:
\xNN
转义序列代表一个字符。当 ruby 处理字符串时,它会注意到“\”并将整个十六进制转义序列转换为一个字符。ruby 处理完字符串后,字符串中的任何地方都没有 \x 了。因此,在字符串中寻找 \x 是徒劳的——它不存在。转义序列中的字符 'f' 和 'e' 也是如此:在 ruby 处理字符串后,它们不存在于字符串中。
请注意,ruby 仅处理双引号字符串中的十六进制转义序列,因此字符串的类型(双引号或单引号)是完全相关的。在单引号字符串中,字符系列 '\xfe' 有四个字符长,因为单引号字符串中不存在十六进制转义序列:
str = "\xfe"
puts str.length #=>1
str = '\xfe'
puts str.length #=>4
正则表达式的行为类似于双引号字符串,因此可以在正则表达式中使用整个转义序列:
/\xfe/
当 ruby 处理正则表达式时,就像使用双引号字符串一样,ruby 将十六进制转义序列转换为单个字符。这允许您在包含相同十六进制转义序列的字符串中搜索单个字符:
if "abc\xfe" =~ /\xfe/
如果您假装 ruby 字符将转义序列“\xfe”转换为字符“z”,那么 if 语句等效于:
if "abcz" =~ /z/
重要的是要意识到正则表达式不是在字符串中搜索 '\' 后跟 'x' 后跟 'f' 后跟 'e'。字符串中不存在这些字符。
inspect() 方法允许您通过取消转义序列来查看字符串中的转义序列,如下所示:
str = "\\xfe\\xff"
puts str
--output:--
\xfe\xff
在双引号字符串中,"\\"
表示文字反斜杠,而转义序列仅以一个斜杠开头。
一旦你取消了转义序列,你就可以匹配文字字符,比如两个字符序列'\x'。但是只选择你想要的部分比匹配你不想要的部分更容易:
str = "\xfe\xff"
str = str.inspect #=> "\"\\xFE\\xFF\""
result = ""
str.scan /x(..)/ do |groups_arr|
result << groups_arr[0]
end
puts result.downcase
--output:--
feff
这是gsub:
str = "\xfe\xff"
str = str.inspect #=>"\"\\xFE\\xFF\""
str.gsub!(/
"? #An optional quote mark
\\ #A literal '\'
x #An 'x'
(..) #Any two characters, captured in group 1
"? #An optional quote mark
/xm) do
Regexp.last_match(1)
end
puts str.downcase
--output:--
feff
请记住,正则表达式的作用类似于双引号字符串,因此要在正则表达式中指定文字 \,您必须编写\\
. 但是,在正则表达式中,您不必担心"
被误认为是正则表达式的结尾,因此您不需要像在双引号字符串中那样对其进行转义。
只是为了好玩:
str = "\xfe\xff"
result = ""
str.each_byte do |int_code|
result << sprintf('%x', int_code)
end
p result
--output:--
"feff"
你为什么叫检查?那是添加额外的引号..
此外,将其放在双引号中意味着 \x 被插值。把它放在单引号中,一切都应该很好。
'\xfe\xff'.gsub("\\x","")
=> "feff"