2

regex 和 ruby​​ 的新手正在寻找一种方法来匹配任何以特定 tld 结尾的域

我有以下电子邮件:

jane.doe@navy.mil
barak.obama@whitehouse.gov
john.doe@usa.army.mil
family@example.com

我正在尝试编写一个正则表达式,它将匹配任何具有顶级域 .mil 和 .gov 的电子邮件,但不匹配其余的。我尝试了以下方法:

/(..).mil/

但我不知道如何让它匹配之前的一切.mil

我正在使用红宝石。这是我在 rubular 中尝试的内容: http: //rubular.com/r/BP7tqgAntY

4

2 回答 2

3

认为你的意思是,

^(.*)\.(?:gov|mil)$

在红宝石中,

string.scan(/^.*(?=\.(?:gov|mil)$)/)

演示

于 2015-09-24T17:43:35.590 回答
1

我会使用类似的东西:

REGEX = /\.(?:mil|gov)$/

%w[
  jane.doe@navy.mil
  barak.obama@whitehouse.gov
  john.doe@usa.army.mil
  family@example.com
].each do |addr|
  puts '"%s" %s' % [addr, (addr[REGEX] ? 'matches' : "doesn't match")]
end
# >> "jane.doe@navy.mil" matches
# >> "barak.obama@whitehouse.gov" matches
# >> "john.doe@usa.army.mil" matches
# >> "family@example.com" doesn't match

如果你知道你想要的 TLD 总是在字符串的末尾,那么一个匹配的简单模式就可以了。

这是有效的,因为addr[REGEX]使用了String 的[]方法,该方法将模式应用于字符串并返回匹配或 nil:

'foo'[/oo/] # => "oo"
'bar'[/oo/] # => nil

如果您想捕获 TLD 之前的所有内容:

REGEX = /(.+)\.(?:mil|gov)$/

%w[
  jane.doe@navy.mil
  barak.obama@whitehouse.gov
  john.doe@usa.army.mil
  family@example.com
].map do |addr|
  puts addr[REGEX, 1]
end
# >> jane.doe@navy
# >> barak.obama@whitehouse
# >> john.doe@usa.army
# >> 

以更“值得生产”的方式使用它:

SELECT_PATTERN = '\.(?:mil|gov)$' # => "\\.(?:mil|gov)$"
CAPTURE_PATTERN = "(.+)#{ SELECT_PATTERN }" # => "(.+)\\.(?:mil|gov)$"

SELECT_REGEX, CAPTURE_REGEX = [SELECT_PATTERN, CAPTURE_PATTERN].map{ |s|
  Regexp.new(s)
}

SELECT_REGEX # => /\.(?:mil|gov)$/
CAPTURE_REGEX # => /(.+)\.(?:mil|gov)$/

addrs = %w[
  jane.doe@navy.mil
  barak.obama@whitehouse.gov
  john.doe@usa.army.mil
  family@example.com
].select{ |addr|
  addr[SELECT_REGEX]
}.map { |addr|
  addr[CAPTURE_REGEX, 1]
}

puts addrs

# >> jane.doe@navy
# >> barak.obama@whitehouse
# >> john.doe@usa.army

同样,您可以在没有正则表达式的情况下执行此操作:

TLDs = %w[.mil .gov]

%w[
  jane.doe@navy.mil
  barak.obama@whitehouse.gov
  john.doe@usa.army.mil
  family@example.com
].each do |addr|
  puts '"%s" %s' % [ addr, TLDs.any?{ |tld| addr.end_with?(tld) } ]
end

# >> "jane.doe@navy.mil" true
# >> "barak.obama@whitehouse.gov" true
# >> "john.doe@usa.army.mil" true
# >> "family@example.com" false

和:

TLDs = %w[.mil .gov]

addrs = %w[
  jane.doe@navy.mil
  barak.obama@whitehouse.gov
  john.doe@usa.army.mil
  family@example.com
].select{ |addr|
  TLDs.any?{ |tld| addr.end_with?(tld) }
}.map { |addr|
  addr.split('.')[0..-2].join('.')
}

puts addrs

# >> jane.doe@navy
# >> barak.obama@whitehouse
# >> john.doe@usa.army

end_with?返回一个真/假字符串是否以该子字符串结尾,这比使用等效的正则表达式要快。any?通过数组查找任何匹配条件并返回真/假。

如果您要检查一长串 TLD,则使用编写良好的正则表达式可能会非常快,甚至可能比使用any?. 这完全取决于您的数据和要检查的 TLD 数量,因此您需要针对数据样本运行基准测试,以了解该走哪条路。

于 2015-09-24T19:31:48.947 回答