2

我有以下十六进制字符串:"\xfe\xff". 我想将其转换为"feff". 我该怎么做呢?

我得到的最接近的是"\xfe\xff".inspect.gsub("\\x", ""),它返回"\"FEFF\""

4

3 回答 3

9
"\xfe\xff".unpack("H*").first
# => "feff"
于 2013-08-25T04:38:49.427 回答
4

您正在处理双引号字符串中的转义序列。双引号字符串中最常见的转义序列是“\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"
于 2013-08-26T06:49:49.343 回答
0

你为什么叫检查?那是添加额外的引号..

此外,将其放在双引号中意味着 \x 被插值。把它放在单引号中,一切都应该很好。

'\xfe\xff'.gsub("\\x","")
 => "feff" 
于 2013-08-25T04:34:55.803 回答