【问题标题】:Regex for First Line (Only) that Contains a String包含字符串的第一行(仅)的正则表达式
【发布时间】:2013-08-21 10:53:56
【问题描述】:

我有一堆电话号码,每行一个:

[Home] (202) 121-7777 
C (202) 456-1111
[mobile] 55 55 5 55555 
[Work] (404) 555-1234 
[Cell] (505) 555-1234
W 303-555-5555
M 777-555-5555
c 12346567s

我想抓取包含大写或小写字母“c”的第一个

到目前为止,我有这个/^.*[C].*$/i,它与C (202) 456-1111[Cell] (505) 555-1234c 12346567s 匹配。我如何只返回第一个?换句话说,匹配应该只是C (202) 456-1111

我一直在盲目输入question marks everywhere,但没有成功。

我正在使用 Ruby,如果它有所作为 http://www.rubular.com/r/h6ReB9IN8t

编辑:这是 Hrishi 指出的another question,但我不知道如何调整它以匹配整行。

【问题讨论】:

  • 也许你应该看看这个问题:stackoverflow.com/questions/519572/…
  • 谢谢。我也看到了那个,但我一定遗漏了一些明显的东西。我会将它添加到引用中,但它并没有解决我的问题。
  • [Cell] (505) 555-1234 编号您的候选解决方案??我的意思是它不是以 C 开头的。

标签: ruby regex


【解决方案1】:

试试match 方法。这是一个例子:

list = <<EOF
[Home] (202) 121-7777 
C (202) 456-1111
[mobile] 55 55 5 55555 
[Work] (404) 555-1234 
[Cell] (505) 555-1234
W 303-555-5555
M 777-555-5555
c 12346567s
EOF

更新

#match line with "c" letter in line, even that are part of word
puts list.match(/^.*C.*$/i) 

#match line with "c" letter in line, that are not a part of word
puts list.match(/^\W*C\W.*$/i) 

【讨论】:

  • 这甚至不起作用 :) 请看看:rubular.com/r/h6ReB9IN8t
  • 我在我的 rubby 中尝试过它,它只返回第一个匹配项。正则表达式匹配 3 个实例,但 match 方法只返回第一个。
  • 这也匹配 [Cell] (505) 555-1234 ,我不太确定问题是否将其视为有效输入。如果是,你的解决方案是正确的,我会支持你:)
  • 如果你只想匹配单词中没有的“c”字母,你可以试试这个正则表达式:rubular.com/r/O7YdvZhCXR
  • /^\W*C\W.*$/i 会比我之前的正则表达式更好。
【解决方案2】:

我会以不同的方式处理这个问题。我更喜欢将正则表达式简化为非常简单的模式:

str = <<EOT
[Home] (202) 121-7777
C (202) 456-1111
[mobile] 55 55 5 55555
[Work] (404) 555-1234
[Cell] (505) 555-1234
W 303-555-5555
M 777-555-5555
c 12346567s
EOT

使用selectfind 可以轻松找到合适的线路:

str.split("\n").select{ |s| s[/c/i] }.first # => "C (202) 456-1111"
str.split("\n").find{ |s| s[/c/i] } # => "C (202) 456-1111"

我推荐find,因为它只返回第一次出现。

找到所需的字符串后,使用scan 获取数字:

str.split("\n").find{ |s| s[/c/i] }.scan(/\d+/) # => ["202", "456", "1111"]

然后join 他们。当您将电话号码存储在数据库中时,您并不真的希望它们被格式化,您只需要这些号码。当您再次输出它们时,稍后会进行格式化。

phone_number = str.split("\n").find{ |s| s[/c/i] }.scan(/\d+/).join # => "2024561111"

当您需要输出号码时,根据地区电话号码表示将其分成正确的分组。你应该知道这个人的位置,因为你通常也知道他们的国家代码。基于此,您知道应该有多少位数,加上组:

area_code, prefix, number = phone_number[0 .. 2], phone_number[3 .. 5], phone_number[6 .. 9] # => ["202", "456", "1111"]

然后输出它们以便正确显示:

"(%s) %s-%s" % [area_code, prefix, number] # => "(202) 456-1111"

就你原来的模式/^.*[C].*$/i来说,你对正则表达式的理解有些问题:

  • ^.* 说“从字符串的开头开始并找到零个或多个字符”,这并不比说 /[C] 更有效。
  • 使用[C] 会创建一个不必要的字符集,这意味着“在集合“C”中查找一个字母;它没有任何用处,所以只需将C 用作/C
  • .*$ 也人为地找到了字符串的结尾,但是由于您没有捕获它,所以什么都没有完成,所以不要理会它。正则表达式现在是 /C/
  • 由于要匹配大小写,请使用/C/i/c/i。 (或者你可以使用/[cC]/,但为什么呢?)

改为:

您可能会变得更复杂,但如果您没有使用额外的模式信息完成任何事情,那么您只是在浪费正则表达式引擎的 CPU 时间,并减慢您的代码。混乱的正则表达式引擎可能会浪费大量 CPU 时间,因此请保持高效并了解您要求它做什么。

【讨论】:

  • 这提供了改进代码的答案和说明。感谢您的努力。
【解决方案3】:

编辑添加了另外两种处理方法。最后一个比较好。

这会做你想做的事。它将搜索您的正则表达式的匹配项,然后获取第一个。请注意,如果字符串没有任何匹配项,这将产生错误。

string = "[Home] (202) 121-7777 
C (202) 456-1111
[mobile] 55 55 5 55555 
[Work] (404) 555-1234 
[Cell] (505) 555-1234
W 303-555-5555
M 777-555-5555
c 12346567s"

puts string.match(/^(.*[C].*)$/i).captures.first
puts string.match(/^(.*[C].*)$/i)
puts string[/^(.*[C].*)$/i]

Ruby Docs String#match.

【讨论】:

    【解决方案4】:

    用换行符分割字符串,select 匹配您要求的子字符串并获取第一个:

    str = '[Home] (202) 121-7777 
    C (202) 456-1111
    [mobile] 55 55 5 55555 
    [Work] (404) 555-1234 
    [Cell] (505) 555-1234
    W 303-555-5555
    M 777-555-5555
    c 12346567s'
    
    p str.split(/\n/).select{|el| el =~ /^.*[C].*$/i}[0]
    

    或使用match:

    p str.match(/^.*[C].*$/i)[0]
    

    编辑:

    或者,如果你想找到第一个以 C 开头的块,试试这个:

    p str.match(/^C.*$/)[0]
    

    【讨论】:

    • 这也匹配 [Cell] (505) 555-1234 ,我不太确定问题是否将其视为有效输入。如果是,你的解决方案是正确的,我会支持你:)
    • 仅供参考,[0] 不是首选的 ruby​​ 语法。你应该使用.first
    • str.match(/^.*[C].*$/i)[0] 有效。我希望得到一个纯粹的正则表达式答案,但这一步完成了工作,没有额外的循环。
    • @sahildhankhar ,你运行代码了吗?两个部分都返回C (202) 456-1111 ;)
    • @screenmutt ,只有意见和风格。我没有看到任何合理的论据。只要不违反语法ruby-doc.org/core-2.0/Array.html#method-i-5B-5D,我可以有自己的风格
    猜你喜欢
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2017-10-02
    • 1970-01-01
    相关资源
    最近更新 更多