0

我试图在我的 Ruby 应用程序中使用以下正则表达式代码来匹配 HTTP 链接,但它会生成无效的输出,在链接后面附加一个句点,有时是句点和一个单词,当在网络上测试时,它会变得无效。

URL_PATTERN  = Regexp.new %r{http://[\w/.%-]+}i
<input>.to_s.scan( URL_PATTERN ).uniq

上面扫描链接的代码有问题吗?

来自应用程序的代码:

require 'bundler/setup'
require 'twitter'

RECORD_LIMIT = 100
URL_PATTERN  = Regexp.new %r{http://[\w/.%-]+}i

def usage
  warn "Usage: ruby #{File.basename $0} <hashtag>"  
  exit 64
end

# Ensure that the hashtag has a hash symbol. This makes the leading '#'
# optional, which avoids the need to quote or escape it on the command line.
def format_hashtag(hashtag)  
  (hashtag.scan(/^#/).empty?) ? "##{hashtag}" : hashtag
end

# Return a sorted list of unique URLs found in the list of tweets.
def uniq_urls(tweets)  
  tweets.map(&:text).grep( %r{http://}i ).to_s.scan( URL_PATTERN ).uniq
end

def search(hashtag)  
  Twitter.search(hashtag, rpp: RECORD_LIMIT, result_type: 'recent')
end

if __FILE__ == $0 usage unless ARGV.size >= 1  
hashtag = format_hashtag(ARGV[0]) 
tweets = search(hashtag) 
puts uniq_urls(tweets)
end
4

3 回答 3

3

TL;博士

人们总是发布不良链接。链接也受到位腐烂。

可能的答案

您是否手动验证了推文?你确定原始推文不包含格式错误的 URL 吗?如果有人发帖:

http://foo.还有吐司吗?

那么你肯定会得到一个无效的结果,因为正则表达式需要 URL 周围的空格。如果您想修剪无效结果,则需要使用可以处理重定向的链接检查器来验证您找到的每个链接。

作者的免责声明

您发布的代码是我的,来自CodeGnome/twitter_url_extractor。我故意省略了链接检查,因为我对提取 URL 感兴趣,而不是验证它们。

“它对我有用;您的里程可能会有所不同。”℠

于 2012-05-28T16:51:59.330 回答
1

与其重新发明轮子,不如使用 Ruby 的URI.extract?它与 Ruby 捆绑在一起。

从文档中:

概要

URI::extract(str[, scheme][,&blk])

精氨酸

str 要从中提取 URI 的字符串。
方案 将 URI 匹配限制为特定方案。

描述

从字符串中提取 URI。如果给出块,则遍历所有匹配的 URI。如果给定块或匹配的数组,则返回 nil。
用法

需要“uri”

URI.extract("这里是 http://foo.example.org/bla 和这里是 mailto:test@example.com 和这里也是。")
# => ["http://foo.example.com/bla", "mailto:test@example.com"]

如果您只想要 HTTP URL:

[3] (pry) main: 0> URI.extract("这里是 http://foo.example.org/bla 和这里是 mailto:test@example.com 和这里也是。", %w[http])
=> [“http://foo.example.org/bla”]
于 2012-05-29T19:26:09.747 回答
1

问题是您的正则表达式将包含一个尾随句点,因为您不加选择地检查单词字符、斜杠、百分号、连字符(又名“减号”)和句点的任意序列。这将捕获一个尾随句点,当 URL 位于句子末尾时,它实际上是标点符号,并且,如果人们省略句点后面的空格,则后面的任何内容 -正如 CodeGnome 正确指出的那样。您可以通过像这样排除尾随标点符号来部分缓解此问题(请注意,这仍然会捕获标点符号,然后是非 URL 内容):

http://\w+(?:[./%-]\w+)+$

但是,这仍然会遗漏大部分现有 URL 并捕获大量无效内容:URL 是相当复杂的野兽。如果你想要一个完美的匹配,John Gruber 发布了一个正则表达式,它匹配今天用作 URL 的任何内容,而不仅仅是 http(s) 的。为了更紧密地匹配大量纯网络 URL,包括 HTTPS 变体,确保您在开始时有一个格式良好的域,并捕获查询和片段标识符,正则表达式应该如下所示:

https?://[\w-]+(?:\.[\w-]+)+(?:/[\w-]+)*(?:(?:[./%?=&#-]\w+)+)?

– 这仍然会捕获无效内容,并排除相当多的现有 URL(以及更大比例的有效 URL – 请参阅我上面链接到的 RFC),但它会让您更接近。

于 2012-05-28T18:59:56.050 回答