1

有一个文件具有分隔文本字段的控制 B 和控制 C 命令。看起来像:

"TEST\003KEY\002TEST\003KEY"

我试图创建一个匹配它并删除它的正则表达式。我不确定为什么这个正则表达式不起作用:

"TEST\003KEY\002TEST\003KEY".gsub(/\00[23]/, ',')
4

3 回答 3

9

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"
于 2013-08-13T20:00:54.347 回答
2

这是交易。首先,计算机不能存储字符——它们只能存储数字。因此,当计算机存储一个字符串时,它会将每个字符转换为一个数字。所有基本字符的数字由 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"

...该字符串不包含字符\012。双引号字符串将该字符序列转换为一个 ascii 代码,该代码表示​​一个字符。你可以很容易地证明这一点:

puts "hello".length        #=>5
puts "hello\012".length    #=>6

还有许多其他类型的转义序列可以出现在双引号字符串中。您会认为它们会列在 String 类文档中,但事实并非如此。

于 2013-08-13T21:54:52.903 回答
1
s = "TEST\003KEY\002TEST\003KEY"
s.split(/[[:cntrl:]]/) * ","
# => "TEST,KEY,TEST,KEY"
于 2013-08-13T20:02:44.883 回答