匹配由分隔符分隔的字符串的某些部分

时间:2015-04-27 20:24:17

标签: ruby regex

我[sic]字符串如:

xx-xxx-xxxxx-xxx-xx
th-asd-welcome-ruk-23
name-lastname-hello

我希望匹配用连字符分隔的第二组字符,例如:xxxasdlastname

我试过了:

  • ^(?:[^-]+-){1}([^-]+),匹配xx-xxx
  • (?<=-)[^\-].+(?=-),匹配xxx-xxxxx-xxx

我如何匹配第二个八位字节?

3 个答案:

答案 0 :(得分:3)

正则表达式不一定是正确的表达方式。首先,我简化了任务:

STRINGS = %w[
  xx-xxx-xxxxx-xxx-xx
  th-asd-welcome-ruk-23
  name-lastname-hello
]

STRINGS.map { |s| s.split('-')[1] }
# => ["xxx", "asd", "lastname"]

将连字符上的字符串拆分为数组,并返回每个数组中找到的第二个项目。

然后我将一个模式与scan结合使用,只找到想要的东西:

STRINGS.map { |s| s.scan(/[^-]+/)[1] }
# => ["xxx", "asd", "lastname"]

找到所有 NOT 连字符的子字符串。

正则表达式对于某些事情很有用,但可能会增加维护问题,有时会超出其价值。它们还可以显着减慢代码速度,仅仅因为它们不是很聪明,并且添加智能需要大量测试和知道引擎将要做什么。所以,仔细去那里,测试/基准,这样你就知道模式和路径是否很快。我编写了很多代码,并指导了很多开发人员,并发现很多地方他们使用了错误的模式,引入了很难检测错误或显着减慢循环。我非常相信基准测试和测试多个路径。

例如:

require 'fruity'

STRINGS = %w[
  xx-xxx-xxxxx-xxx-xx
  th-asd-welcome-ruk-23
  name-lastname-hello
]

compare do
  split { STRINGS.map { |s| s.split('-')[1] } }
  scan { STRINGS.map { |s| s.scan(/[^-]+/)[1] } }
end
# >> Running each test 1024 times. Test will take about 1 second.
# >> split is faster than scan by 4x ± 0.1

根据我的经验,我知道split的运行速度比使用模式的scan要快。

根据经验,我也知道模式可以非常快。测试模式的变化并提取记录:

require 'fruity'

STRINGS = %w[
  xx-xxx-xxxxx-xxx-xx
  th-asd-welcome-ruk-23
  name-lastname-hello
]

compare do
  split { STRINGS.map { |s| s.split('-')[1] } }
  scan { STRINGS.map { |s| s.scan(/[^-]+/)[1] } }
  slice { STRINGS.map { |s| s[/^(?:[^-]+)-([^-]+)/, 1] } }

  stribizhev { STRINGS.map { |s| s.match(/(?<=-)[^-]+(?=-)/)[0] } }
end
# >> Running each test 2048 times. Test will take about 1 second.
# >> slice is faster than split by 60.00000000000001% ± 10.0%
# >> split is faster than stribizhev by 1.9x ± 0.1
# >> stribizhev is faster than scan by 80.0% ± 10.0%

所以,那个是你应该做的,以确定要遵循的路径。然后权衡维护成本:是否更容易维护s.split('-')[1]s[/^(?:[^-]+)-([^-]+)/, 1]

并且,最后一个模式超越简单split的原因是非常快,因为模式是锚定的。锚定模式为引擎提供了一个令人难以置信的有用提示,即如何找到它所使用的所需模式。它也不需要任何回溯,这会浪费引擎的CPU时间,而引擎可以继续期待找到它想要的东西。

答案 1 :(得分:1)

只需删除点并使用以下正则表达式:

(?<=-)[^\-]+(?=-)

或者不使用环视使用捕获组:

-([^\-]+)-

Demo

答案 2 :(得分:1)

你的两个模式都太贪心了。 [^-]+.+将消耗尽可能多的字符。请注意[^\-].+并不意味着&#34;除了连字符之外的任何数量的字符&#34;。这意味着&#34;匹配1个非连字符,然后匹配任何字符,尽可能多的&#34;。

使用/(?<=-)[^-]+(?=-)/的简单match可以做到这一点:

puts "th-asd-welcome-ruk-23".match(/(?<=-)[^-]+(?=-)/)

或简单(没有正则表达式):

puts "th-asd-welcome-ruk-23".split("-")[1]

输出:

asd

请参阅TutorialsPoint demo