我正在尝试通过数字字符在字符串中的位置来匹配它们。例如,在字符串"1234567"
中,我想选择第二个到第四个字符:"234"
。"D9873Y.31"
也应该出现"987"
。你有什么建议吗?
问问题
67 次
3 回答
5
你不需要正则表达式,你可以使用String#[]
:
s = '1234567'
s[1..3] #=> "234"
s = 'D9873Y.31'
s[1..3] #=> "987"
于 2013-06-12T00:53:13.210 回答
2
您可以为此使用正则表达式,并且模式足够灵活,可以用几种不同的方式编写它们。我尽量让它们保持简单,因为它们的神秘性质可能会成为维护的噩梦:
"1234567"[/^.(.{3})/, 1]
=> "234"
"D9873Y.31"[/^.(.{3})/, 1]
=> "987"
"1234567".match(/^.(.{3})/)[1]
=> "234"
"D9873Y.31".match(/^.(.{3})/)[1]
=> "987"
您还可以利用命名捕获:
/^.(?<chars2_4>.{3})/ =~ "1234567"
chars2_4
=> "234"
/^.(?<chars2_4>.{3})/ =~ "D9873Y.31"
chars2_4
=> "987"
这一切都很好,但是深入研究并很好地学习它们非常重要,因为如果做错了,您可能会获取错误的数据,或者更糟的是,通过使正则表达式引擎非常努力地做一些简单的事情,真的会减慢您的脚本。
比如我^
上面用的。^
匹配行的开头,即字符串的开头和紧跟换行符的字符。这对于短字符串是可以的,但是长字符串,尤其是嵌入换行符的长字符串会减慢引擎的速度。相反,您可能想使用\A
. 同样的情况也适用于使用$
or\Z
或\z
。这是来自“锚”的正则表达式文档部分:
^
- 匹配行首$
- 匹配行尾\A
- 匹配字符串的开头。\Z
- 匹配字符串的结尾。如果字符串以换行符结尾,则在换行符之前匹配\z
- 匹配字符串的结尾
这就是为什么您有时希望避免使用正则表达式,而是使用@AndrewMarshall 推荐的子字符串。
这是为什么简单的子字符串方式更可取的另一个原因:
require 'benchmark'
N = 1_000_000
Benchmark.bm(13) do |b|
b.report('string index') { N.times {
"1234567"[1..3]
"D9873Y.31"[1..3]
} }
b.report('regex index') { N.times {
"1234567"[/^.(.{3})/, 1]
"D9873Y.31"[/^.(.{3})/, 1]
} }
b.report('match') { N.times {
"1234567".match(/^.(.{3})/)[1]
"D9873Y.31".match(/^.(.{3})/)[1]
} }
b.report('named capture') { N.times {
/^.(?<chars2_4>.{3})/ =~ "1234567"
/^.(?<chars2_4>.{3})/ =~ "D9873Y.31"
} }
b.report('look behind') { N.times {
"1234567"[/(?<=^.{2}).{3}/, 1]
"D9873Y.31"[/(?<=^.{2}).{3}/, 1]
} }
end
返回:
user system total real
string index 0.730000 0.000000 0.730000 ( 0.727323)
regex index 1.370000 0.000000 1.370000 ( 1.377121)
match 4.400000 0.000000 4.400000 ( 4.398849)
named capture 5.240000 0.010000 5.250000 ( 5.243799)
look behind 1.430000 0.000000 1.430000 ( 1.437286)
于 2013-06-12T03:55:46.737 回答
1
您可以使用带有锚点的lookbehind来做到这一点,例如:
(?<=^.{2}).{3}
会给你345
于 2013-06-12T00:53:53.907 回答