根据您希望匹配的 3 种 URL 中的哪一种,可以对问题做出不同的回答:
仅完全匹配(字符串相等)。例如,如果 DB url 是“google.com”,那么搜索字符串“ http://google.com ”将不匹配,“google.com/q=a”也不会匹配。
在这种情况下,放弃使用正则表达式,或者简单地做SELECT * FROM urls WHERE url="$search"
,或者做一个哈希查找作为 Andreas 的答案细节。
搜索 URL 和 DB 中的 URL 都是有效 URL(例如以 http:// 开头),因此必须从字符串开头匹配,但搜索 URL 可以包含要匹配的 DB URL+后缀。例如,如果 DB URL 是“ http://google.com ”,则搜索字符串“ http://google.com ”和“ http://google.com/q=a ”匹配。
在这种情况下,要么开始锚定正则表达式,要么开始锚定“LIKE”数据库匹配 - 请参阅答案下一部分中的详细信息。
任何子字符串匹配。例如,如果 DB URL 是“google”,那么任何包含“google”字符串的 URL 都匹配任何地方。
在这种情况下,要么做单词查找表,要么做更智能的子串查找算法;或使用“|”进行批量正则表达式匹配 加入多个数据库网址。请参阅答案的最后一部分中的详细信息。
这部分答案假设您在 DB 中的 URL 可以是搜索 URL 的子字符串,但它们都以“http”开头,这意味着它们始终在字符串的开头匹配;但不是完全匹配。
开始锚定匹配的解决方案 1 (Perl):
将您的正则表达式固定在开头:if($searchedurl=~ /^$_/){
开始锚定匹配 (DB) 的解决方案 2:
按 URL 字段索引您的 URL 表,然后执行(Sybase 语法)
$query = qq[SELECT * FROM urls WHERE url LIKE "$searchurl\%"];
这将对开始锚定的子字符串进行非常有效的数据库搜索。
注意:在 DB 和 Perl 中进行匹配之间的权衡是:
这部分答案假设您在 DB 中的 URL 可以是搜索 URL 的完整子字符串,不一定是完全匹配甚至是锚定匹配。
随机子字符串匹配的解决方案 1 (Perl):
一种可以加快速度的纯粹 Perl 方法是将搜索字符串组合成批处理:
@urldb
在循环中从 , 中分离出前 N 个元素
my $N = 10;
my $start = 0;
my $end = $N - 1;
while ($start < @urldb ) {
search_with($searchedurl, @urldb[$start..$end]); # see next bullet
$start += $N;
$end += $N;
$end = @urldb if $end > @urldb;
}
对于每个长度为 N 的数组,用“|”连接元素 并创建一个正则表达式
sub search_with {
my $searchedurl = shift;
my $regex_string = join("|", @_);
if ($searchedurl =~ /($regex_string)/) {
# Do stuff, $1 will contain what matched.
}
}
随机子字符串匹配 (DB) 的解决方案 2:
另一种更具算法性的方法是构建一个“单词查找”表(也称为索引,但我宁愿不使用术语索引以避免与数据库索引混淆)。
- 将每个 URL 拆分为单词。
- 在数据库中,将唯一 ID 添加到 URL 表
- 在数据库中,将“单词查找”表映射(1 对 N)URL ID 添加到该 URL 中的每个单词(每行 1 个)
- 使用“单词查找”表缩小要查询的 URL 列表。
- 您可以在“单词查找”表上使用数据库索引来使搜索速度非常快。
- 当然,您还需要将搜索 URL 拆分为单词。
- 通过从路径中单独索引域名词进一步加速/缩小。
注意:如果 URL 可以是与第一个字符不匹配的子字符串,则在数据库中使用简单的“WHERE”子句来搜索您的 URL 表是一个非常糟糕的主意 - 这样,您就不能使用和索引并且会只需扫描表格。
注意2:为了更有效地匹配字符串数组的子字符串,有更高级的基于子字符串图的算法。
注意 3:在 Perl 和 DB 中进行匹配之间的权衡与答案的前半部分相同。