【问题标题】:Ruby regex without global flag没有全局标志的 Ruby 正则表达式
【发布时间】:2020-01-11 09:23:27
【问题描述】:

我有一个正则表达式问题。我有这个正则表达式:

/(https|http):\/\/(kwagmire)\.(com)\/(embed)\/([a-zA-Z0-9]+)/i

这在 https://regexr.com 上正确捕获,但在 Ruby on Rails 上任何带有

的内容
http://kwagmire.com/embed/1QgJVmCam

返回一个真实的值,我认为是因为它设置了我不想要的 global 标志。

我尝试了matchscan,但如果看到链接,仍然会返回一个真实值。我只是想让它具体一点。

https://kwagmire.com/embed/1QgJVmCam < I want to return success this one is ok when testing on console

http://kwagmire.com/embed/1QgJVmCam < I want to return success also this on returns good

https.evil.com/http://jsitor.com/embed/1QgJVmCam < I want to return fail or nil, this one passes returns all match

facebook.com < I want to return fail or nil this one is good because it's failing

https://google.com < I want to return fail or nil also this good failed
www.twitter.com < I want to return fail or nil

http://kwagmire.com/embed/1QgJVmCam/?onload(alert('asdfadsf')) < I want to return fail or nil, this one also is failing, good

http://kwagmire.com/embed/1QgJVmCam/   onload(alert('asdfadsf')) < I want to return fail or nil, this one returns match too but should fail

http://kwagmire.com/embed/1QgJVmCam/?onload(alert('asdfadsf')) < I want to return fail or nil, this one returns match too, this should fail

基本上我想要这个https://kwagmire.com/embed/1QgJVmCam 其他的都应该返回 nil 或 false。有没有不循环的简单方法?我认为这个解决方案是删除全局标志或g,但你有这个选项吗?如果是这样,我为什么要这样做?

查看/之后的i

/(https|http):\/\/(jsitor)\.(com)\/(embed)\/([a-zA-Z0-9]+)/i.match("http://jsitor.com/embed/1QgJVmCam/ onload(alert('asdfadsf'))")

然后返回,但这应该会失败

#<MatchData "http://jsitor.com/embed/1QgJVmCam" 1:"http" 2:"jsitor" 3:"com" 4:"embed" 5:"1QgJVmCam">

【问题讨论】:

  • 您能更具体地说明您想要实现的目标吗?你能提供一些你想要匹配和不应该匹配的链接的测试链接吗?
  • @allenbrkn 检查 &lt; 之前的文本我编辑了它
  • 对于它的价值,这不是关于 Rails 的问题。这是一个关于纯 Ruby 的问题。
  • 与其尝试编写一个对于 URI 来说很复杂的正则表达式,不如使用 Ruby 的 URI 类,它已经编写好并且可以工作,它允许您将路径分解为其组件,然后检查它们分别。特别是看splitparse
  • 您需要根据您想要实现的目标来陈述您的问题,不参考正则表达式。也就是说,您有许多要测试的字符串。只有一个通过了测试。测试是什么?这就是您需要构建问题的方式。完成后,您可以展示您尝试过的正则表达式,并解释它为什么不起作用。最后,别再猜测为什么正则表达式不起作用了。

标签: regex ruby


【解决方案1】:

看起来您只需要在正则表达式的开头和结尾处使用^$,或者更好的是\A\Z 来标记整个字符串的开头和结尾(^$ 只要是单行就可以工作)。

这告诉 Ruby 它必须从头到尾匹配。最后的“i”也不是必需的,可能会产生不正确的结果。

以下修改的正则表达式将起作用。

/\A(https|http):\/\/(kwagmire)\.(com)\/(embed)\/([a-zA-Z0-9]+)\/?\Z/

请注意,除了\A\Z,我还添加了\/?,它允许在网址末尾添加可选的/。最后我还删除了i,因为您实际上并不希望 entire 正则表达式不区分大小写。最后一部分([a-zA-Z0-9]+) 已经不区分大小写,因为它是如何用 a-z 和 A-Z 声明的。

myregex.match("http://kwagmire.com/embed/1QgJVmCa/?onload(alert('asdfadsf'))") 返回 nil

myregex.match("http://kwagmire.com/embed/1QgJVmCam/") 返回 #&lt;MatchData "http://kwagmire.com/embed/1QgJVmCam/" 1:"http" 2:"kwagmire" 3:"com" 4:"embed" 5:"1QgJVmCam"&gt;

【讨论】:

  • 先生,我想就是这样。这就是我想要的。我知道有一种简单的方法无需循环,因为我知道 url 将是什么。在我忘记之前,我已经在 javascript 中使用了类似的方式。谢谢你! @randall
  • 我也添加了这个 \A 和 \Z 但在 regexr.com 它说字面 A 这就是我不使用它的原因。
【解决方案2】:

我猜,

(?im)^https?:\/\/(?:w{3})?kwagmire\.com\/embed\/([a-zA-Z0-9]+)\/?$

可能工作正常。

测试

re = /^https?:\/\/(?:w{3})?kwagmire\.com\/embed\/([a-zA-Z0-9]+)\/?$/im
str = 'https://kwagmire.com/embed/1QgJVmCam
http://kwagmire.com/embed/1QgJVmCam
https.evil.com/http://jsitor.com/embed/1QgJVmCam
facebook.com
https://google.com
www.twitter.com
http://kwagmire.com/embed/1QgJVmCam/?onload(alert(\'asdfadsf\'))
http://kwagmire.com/embed/1QgJVmCam/   onload(alert(\'asdfadsf\'))'

str.scan(re) do |match|
    puts match.to_s
end

输出

["1QgJVmCam"]
["1QgJVmCam"]

正则表达式电路

jex.im 可视化正则表达式:


如果您希望简化/修改/探索表达式,在regex101.com 的右上角面板中已对此进行了说明。如果您愿意,您还可以在this link 中观看它如何与一些示例输入匹配。


【讨论】:

  • 对不起先生,这不起作用。我在想regex_without_global.match('https://kwagmire.com/embed/1QgJVmCam') return truthy regex_without_global.match('https://kwagmire.com/embed/1QgJVmCam/?evilevil') return nil
  • 对于 ruby​​,^$ 始终匹配行的开头和结尾,并且 m 修饰符允许点匹配换行符。
  • @CasimiretHippolyte 但是当我尝试他的方法时它只是给了我一个空数组
【解决方案3】:

有些人在遇到问题时会想“我知道,我会用 正则表达式。”现在他们有两个问题。

Ruby 有 URI module,它实际上解析 URI 并理解它们。在实际使用 URI 时,它几乎可以击败任何正则表达式。

输入:

input = ["https://kwagmire.com/embed/1QgJVmCam", "http://kwagmire.com/embed/1QgJVmCam", "https.evil.com/http://jsitor.com/embed/1QgJVmCam", "facebook.com", "https://google.com", "www.twitter.com", "http://kwagmire.com/embed/1QgJVmCam/?onload(alert('asdfadsf'))", "http://kwagmire.com/embed/1QgJVmCam/   onload(alert('asdfadsf'))"]
require 'uri'

# This assumes that the id is 9 characters
re =  /\A\/embed\/[\d|a-zA-Z]{9}\/?\Z/.freeze
clean = input.map do |line|
  begin
    uri = URI(line)
    if uri.host == 'kwagmire.com' && uri.path =~ re && !uri.query
      uri.to_s
    end
  rescue URI::InvalidURIError
    nil
  end
end.compact

输出:

["https://kwagmire.com/embed/1QgJVmCam", "http://kwagmire.com/embed/1QgJVmCam"]

这使您可以使用更简单的正则表达式来验证路径,您也可以只使用uri.path.split('/') 并完全放弃正则表达式。它还保证您正在处理一个有效的 URI。

【讨论】:

    猜你喜欢
    • 2014-06-27
    • 1970-01-01
    • 2011-04-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 2018-07-17
    • 2018-05-23
    • 1970-01-01
    相关资源
    最近更新 更多