有一个文件具有分隔文本字段的控制 B 和控制 C 命令。看起来像:
"TEST\003KEY\002TEST\003KEY"
我试图创建一个匹配它并删除它的正则表达式。我不确定为什么这个正则表达式不起作用:
"TEST\003KEY\002TEST\003KEY".gsub(/\00[23]/, ',')
有一个文件具有分隔文本字段的控制 B 和控制 C 命令。看起来像:
"TEST\003KEY\002TEST\003KEY"
我试图创建一个匹配它并删除它的正则表达式。我不确定为什么这个正则表达式不起作用:
"TEST\003KEY\002TEST\003KEY".gsub(/\00[23]/, ',')
Try the following:
"TEST\003KEY\002TEST\003KEY".gsub(/\002|\003/, ',')
Here it is demonstrated in irb
on my machine:
$ irb
1.9.3p448 :007 > "TEST\003KEY\002TEST\003KEY".gsub(/\002|\003/, ',')
=> "TEST,KEY,TEST,KEY"
The syntax \002|\003
means "match the character literal \002
or the character literal \003
". The expression given in the original question \00[23]
is not valid: this is the character literal \00
(a null character) followed by the character class [23]
: i.e. it matches two-character sequences.
You can also use the [[:cntrl:]]
character class to match all control characters:
$ irb
1.9.3p448 :007 > "TEST\003KEY\002TEST\003KEY\005TEST".gsub(/[[:cntrl:]]/, ',')
=> "TEST,KEY,TEST,KEY,TEST"
这是交易。首先,计算机不能存储字符——它们只能存储数字。因此,当计算机存储一个字符串时,它会将每个字符转换为一个数字。所有基本字符的数字由 ascii 图表给出(你可以在谷歌搜索一个)。
当您告诉计算机打印字符串时,它会检索为字符串保存的数字并将它们作为字符输出(使用 ascii 图表将数字转换为字符)。
双引号字符串可以包含所谓的转义序列。最常见的转义序列是“\n”:
puts "hello\nworld"
--output:--
hello
world
双引号字符串将转义序列“\n”转换为 ascii 代码 10:
puts "\n".ord #=>10 (ord() will show you the ascii code for a character)
双引号字符串也可以包含\ddd 形式的转义序列,例如\002。像这样的转义序列称为八进制转义序列,这意味着 002 是 ascii 代码的八进制表示。
在八进制数中,最右边的数字是 1 的列,左边的下一个数字是 8 的列,左边的下一个数字是 64 的列。例如,这个八进制数:
\123
相当于 3*1 + 2*8 + 1*64 = 83。碰巧“S”的 ascii 代码为 83:
puts "\123" #=>S
因为您也可以在双引号字符串中使用八进制转义序列,这意味着您可以使用八进制转义“\012”(2*1 + 1*8 + 0*64 = 10)。双引号字符串将八进制转义序列“\012”转换为 ascii 代码 10,这与双引号字符串对“\n”的作用相同。这是一个例子:
puts "hello" + "\012" + "world"
--output:--
hello
world
关于八进制转义序列最后要注意的是,您可以选择省略任何前导 0:
puts "hello" + "\12" + "world"
--output:--
hello
world
好的,现在检查您的字符串:
"TEST\003KEY\002TEST\003KEY"
您可以看到它包含三个八进制转义序列。双引号字符串将八进制转义序列 \003 转换为 ascii 码:3*1 + 0*8 + 0*64 = 3。如果查看 ascii 图表,ascii 码 3 表示一个称为“文本结尾”的字符. 双引号字符串将八进制转义序列 \002 转换为 ascii 代码:2*1 + 0*8 + 0*64 = 2,它表示一个称为“文本开头”的字符。我不确定您从哪里获得“控制 B”和“控制 C”名称(也许这些是映射到这些字符的键盘上的击键?)。
接下来,正则表达式就像一个双引号字符串,所以
/<in here>/
您可以使用与双引号字符串中相同的转义序列,并且正则表达式会将转义序列转换为 ascii 代码。
现在,根据上述所有内容,检查您的正则表达式:
/\00[23]/
正如 Richard Cook 指出的那样,您的正则表达式被解释为八进制转义序列 \00 后跟字符类 [23]。八进制转义序列 \00 被转换为 ascii 代码:0*1 + 0*8 = 0。如果您查看 ascii 图表,数字 0 表示一个称为“null”的字符。所以你的正则表达式正在寻找一个空字符,后跟一个“2”或“3”,这意味着你的正则表达式正在寻找一个两个字符串。但是两个字符的字符串永远不会匹配八进制转义序列“\003”(或“\002”),它只表示一个字符。
从这一切中得到的主要好处是,当您看到一个包含八进制转义序列的字符串时:
"hello\012world"
...该字符串不包含字符\
、0
、1
和2
。双引号字符串将该字符序列转换为一个 ascii 代码,该代码表示一个字符。你可以很容易地证明这一点:
puts "hello".length #=>5
puts "hello\012".length #=>6
还有许多其他类型的转义序列可以出现在双引号字符串中。您会认为它们会列在 String 类文档中,但事实并非如此。
s = "TEST\003KEY\002TEST\003KEY"
s.split(/[[:cntrl:]]/) * ","
# => "TEST,KEY,TEST,KEY"