我正在尝试在Ruby中编写一个正则表达式,我想查看该字符串是否包含某个单词(例如“string”),后跟括号中的url和链接名称。
现在我正在做:
string.include?("string") && string.scan(/\(([^\)]+)\)/).present?
我在两个条件中的输入都是一个字符串。在第一个中,我正在检查它是否包含单词“link”,然后我将在括号中包含link和link_name,如下所示:
"Please go to link( url link_name)"
验证完毕后,我提取HTML链接。
有没有办法可以使用正则表达式组合它们?
答案 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不是。匹配不区分大小写,因此它与link
和LINK
完全相同。
您可以使用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*
更改为[^\(]*
,你就应该好了。