如何在一个正则表达式中组合这两个Ruby字符串测试?

时间:2016-05-11 18:32:52

标签: ruby-on-rails ruby regex string ruby-on-rails-4

我正在尝试在Ruby中编写一个正则表达式,我想查看该字符串是否包含某个单词(例如“string”),后跟括号中的url和链接名称。

现在我正在做:

string.include?("string") && string.scan(/\(([^\)]+)\)/).present?

我在两个条件中的输入都是一个字符串。在第一个中,我正在检查它是否包含单词“link”,然后我将在括号中包含link和link_name,如下所示:

"Please go to link( url link_name)"

验证完毕后,我提取HTML链接。

有没有办法可以使用正则表达式组合它们?

4 个答案:

答案 0 :(得分:3)

您可以做的最重要的改进是测试单词和括号中的正确关系。如果我理解正确,WithDegreeOfParallelism()应该匹配,但"link(url link_name)""(url link_name)link"不应该匹配。所以匹配"link stuff (url link_name)",括号及其内容,并一次性捕获内容:

"link"

&. is Ruby 2.3;在旧版本中使用Rails'"stuff link(url link_name) more stuff".match(/link\((\S+?) (\S+?)\)/)&.captures => ["url", "link_name"] 。)

附注:.try :captures更简洁地写为string.scan(regex).present?

答案 1 :(得分:2)

检查是否包含Word

如果您想在字符串中的某处找到包含特定单词的匹配项,您可以通过前瞻来完成此任务:

# This will match any string that contains your string "{your-string-here}"
(?=.*({your-string-here}).*).*

您可以考虑构建表达式的字符串版本,并使用变量传递您要查找的单词:

wordToFind = "link"
if stringToTest =~ /(?=.*(#{wordToFind}).*).*/
    # stringToTest contains "link"
else
    # stringToTest does not contain "link"
end

检查Word和括号

如果您还想确保字符串中的某个位置有一组带有一些内容的括号您以前的单词前瞻,则可以使用:

# This will match any strings that contain your word and contain a set of parentheses 
(?=.*({your-string-here}).*).*\([^\)]+\).*

可能用作:

wordToFind = "link"
if stringToTest =~ /(?=.*(#{wordToFind}).*).*\([^\)]+\).*/
    # stringToTest contains "link" and some non-empty parentheses
else
    # stringToTest does not contain "link" or non-empty parentheses
end

答案 2 :(得分:2)

def has_both?(str, word)
  str.scan(/\b#{word}\b|(?<=\()[^\(\)]+(?=\))/).size == 2
end

has_both?("Wait for me, Wild Bill.", "Bill")
  #=> false 
has_both?("Wait (for me), Wild William.", "Bill")
  #=> false 
has_both?("Wait (for me), Wild Billy.", "Bill")
  #=> false 
has_both?("Wait (for me), Wild bill.", "Bill")
  #=> false 
has_both?("Wait (for me, Wild Bill.", "Bill")
  #=> false 
has_both?("Wait (for me), Wild Bill.", "Bill")
  #=> true 
has_both?("Wait ((for me), Wild Bill.", "Bill")
  #=> true 
has_both?("Wait ((for me)), Wild Bill.", "Bill")
  #=> true 

这些是

的计算
word = "Bill"
str = "Wait (for me), Wild Bill."

r = /
    \b#{word}\b  # match the value of the variable 'word' with word breaks for and aft
    |         # or
    (?<=\()   # match a left paren in a positive lookbehind
    [^\(\)]+  # match one or more characters other than parens
    (?=\))    # match a right paren in a positive lookahead
    /x        # free-spacing regex definition mode
  #=> /
      \bBill\b  # match the value of the variable 'word' with word breaks for and aft
      |         # or
      (?<=\()   # match a left paren in a positive lookbehind
      [^\(\)]+  # match one or more characters other than parens
      (?=\))    # match a right paren in a positive lookahead
      /x 

arr = str.scan(r)
  #=> ["for me", "Bill"]
arr.size == 2
  #=> true

答案 3 :(得分:1)

我会选择这样的正则表达式:

/link\s*\(([^\)\s]+)\s*([^\)]+)?\)/i

这将找到以单词link开头的任何匹配项,后跟任意数量的空格,然后是圆括号中的网址后跟链接名称。在此正则表达式中,链接名称是可选的,但URL不是。匹配不区分大小写,因此它与linkLINK完全相同。

您可以使用Regexp#match方法将正则表达式与字符串进行比较,并检查匹配和捕获的结果,如下所示:

m = /link\s*\(([^\)\s]+)\s*([^\)]+)?\)/i.match("link (stackoverflow.com StackOverflow)")
if m  # the match array is not nil
  puts "Matched: #{m[0]}"
  puts " -- url: {m[1]}"
  puts " -- link-name: #{m[2] || 'none'}"
else  # the match array is nil, so no match was found
  puts "No match found"
end

如果您想使用不同的字符串来识别匹配项,可以使用非捕获组,将link更改为:

(?:link|site|website|url)

在这种情况下,(?:语法表示不捕获匹配的这一部分。如果要捕获匹配的术语,只需将其从(?:更改为(,然后将捕获索引调整为1以考虑新的捕获值。

这是一个简短的Ruby测试程序:

data = [
  [ true, "link (http://google.com Google)", "http://google.com", "Google" ],
  [ true, "LiNk(ftp://website.org)", "ftp://website.org", nil ],
  [ true, "link   (https://facebook.com/realstanlee/ Stan Lee) linkety link", "https://facebook.com/realstanlee/", "Stan Lee" ],
  [ true, "x  link (https://mail.yahoo.com Yahoo! Mail)", "https://mail.yahoo.com", "Yahoo! Mail" ],
  [ false, "link lunk (http://www.com)", nil, nil ]
]

data.each do |test_case|
  link = /link\s*\(([^\)\s]+)\s*([^\)]+)?\)/i.match(test_case[1])
  url = link ? link[1] : nil
  link_name = link ? link[2] : nil
  success = test_case[0] == !link.nil?  && test_case[2] == url && test_case[3] == link_name
  puts "#{success ? 'Pass' : 'Fail'}: '#{test_case[1]}' #{link ? 'found' : 'not found'}"
  if success && link
    puts " -- url: '#{url}' link_name: '#{link_name || '(no link name)'}'"
  end
end

这会产生以下输出:

Pass: 'link (http://google.com Google)' found
 -- url: 'http://google.com' link_name: 'Google'
Pass: 'LiNk(ftp://website.org)' found
 -- url: 'ftp://website.org' link_name: '(no link name)'
Pass: 'link   (https://facebook.com/realstanlee/ Stan Lee) linkety link' found
 -- url: 'https://facebook.com/realstanlee/' link_name: 'Stan Lee'
Pass: 'x  link (https://mail.yahoo.com Yahoo! Mail)' found
 -- url: 'https://mail.yahoo.com' link_name: 'Yahoo! Mail'
Pass: 'link lunk (http://www.com)' not found

如果你想在“link”和第一个词之间允许除空格以外的任何内容,只需将\s*更改为[^\(]*,你就应该好了。