考虑链接
https://unix.stackexchange.com/questions/tagged/linux?page=2&sort=newest&pagesize=15 https://unix.stackexchange.com/questions/tagged/linux?page=3&sort=newest&pagesize=15 https://unix.stackexchange.com/questions/tagged/linux?page=4&sort=newest&pagesize=15
这里'page'是递增的,如果有115页那么最后一页的page值将是115
如何通过处理 2 个示例链接来知道链接的哪一部分正在递增?
我需要使用 shell 脚本生成所有 115 个链接。
输入将是第 2 页和第 3 页的 2 个链接以及总页数。
我用的是bash shell,python也可以
答案1
这是一个 Perl 脚本,只是为了展示如何使用 Perl 的按位异或 (XOR) 运算符 ( ^
)。
剧本
我叫它cmp.pl
。
#!/usr/bin/perl -w
use strict;
use warnings;
# $s1 = "http://unix.stackexchange.com/questions/tagged/linux?page=2&sort=newest&pagesize=15";
# $s2 = "http://unix.stackexchange.com/questions/tagged/linux?page=3&sort=newest&pagesize=15";
# $np = 115
my $s1 = $ARGV[0];
my $s2 = $ARGV[1];
my $np = $ARGV[2];
my $posOfDiff;
my $mask = $s1 ^ $s2;
while ($mask =~ /[^\0]/g) {
$posOfDiff = $-[0];
}
for (my $idx = 1; $idx <= $np; $idx++) {
my $newStr = $s1;
substr($newStr,$posOfDiff,1) = $idx;
print "$newStr\n";
}
细节
该脚本的独特之处在于使用了 Perl 的 ( ^
) 运算符。这种方法的强大之处在于这段代码:
my $mask = $s1 ^ $s2;
while ($mask =~ /[^\0]/g) {
$posOfDiff = $-[0];
}
上面将$mask
使用 2 个字符串创建一个掩码 ( )。 XOR 掩码是一个向量,其中$s1
和之间匹配的值包含 0 $s2
,不同的值包含 1。如果您想说服自己这一点,可以添加这行代码:
my $mask = $s1 ^ $s2;
printf "[$_] is 0x%02x\n", ord($_) for split //, $mask;
面膜的内脏
这printf
将产生这样的输出。笔记:这些字符是不可打印的,它们是十六进制值。 0x00 是空字符的十六进制值,0x01 是 1。
...
[] is 0x00
[] is 0x00
[] is 0x00
[] is 0x00
[] is 0x00
[ ] is 0x01
[] is 0x00
[] is 0x00
...
当任何非 0 的值表示值不同时返回的值。其他例子:
$ perl -we '$a="ab"; $b="ac"; $c=$a ^ $b; printf "[$_] is 0x%02x\n", ord($_) for split //, $c;'
[] is 0x00
[] is 0x01
$ perl -we '$a="ab"; $b="ad"; $c=$a ^ $b; printf "[$_] is 0x%02x\n", ord($_) for split //, $c;'
[] is 0x00
[] is 0x06
$ perl -we '$a="ab"; $b="ae"; $c=$a ^ $b; printf "[$_] is 0x%02x\n", ord($_) for split //, $c;'
[] is 0x00
[] is 0x07
循环遍历蒙版
循环的另一个有趣的功能是它仅循环不为空的while
字符( )。因此,在您的示例中,我们实际上只执行 while 循环 1 次,因为 2 个字符串之间只有 1 个差异。如果有 2 个差异,则会执行 2 次。所以这是一个相当有效的方法。$mask
\0
如果您需要更有说服力,您可以添加一些额外的代码行来显示while
正在运行的循环:
while ($mask =~ /[^\0]/g) {
print "in the loop\n";
print "what we're looking for:" . $-[0] . "\n";
这些行仅显示一次:
in the loop
what we're looking for:58
保存差异的位置
一旦找到匹配项,就会执行 while 循环的主体,并将位置记录在变量 中$posOfDiff
。如何?这里的美妙之处在于变量 $-[0] 的使用。这将为我们提供最后一次成功匹配的位置的偏移量。
$-[0] 是最后一次成功匹配的开始位置的偏移量。
这个匹配是在循环的控制部分中发生的while
,我们正在寻找$mask
不是空字符(\0
)的字符,因此我们的差异字符:
$mask =~ /[^\0]/g
笔记:尾部g
告诉 Perl 中的匹配函数在全局范围内执行此操作,因此它将继续查找匹配项,直到耗尽字符串$mask
。
还有什么?
该脚本的其余部分几乎是 Perl 的样板,不值得进一步讨论。
参考
答案2
在Python中你可以使用SequenceMatcher
从difflib
:
#!/usr/bin/env python
import difflib
url1 = "http://unix.stackexchange.com/questions/tagged/linux?page=2&sort=newest&pagesize=15"
url2 = "http://unix.stackexchange.com/questions/tagged/linux?page=3&sort=newest&pagesize=15"
matcher = difflib.SequenceMatcher(a=url1, b=url2)
matches = matcher.get_matching_blocks()
prefix = url1[:matches[0][2]]
suffix = url2[matches[1][1]:]
for i in range(2, 116):
print prefix + str(i) + suffix
SequenceMatcher.get_matching_blocks()
将返回形式为 的三元组列表(i, j, n)
,其中a[i:i+n] == b[j:j+n]
.使用前两个这样的三元组,我们构建了围绕页码的 URL 的前缀和后缀,并迭代 URL 的范围。
答案3
在不了解有关链接的任何其他信息并假设仅页码发生变化的情况下,这是我的方法。首先我想到了diff -e
,但事实证明它只是创建了一个整行ed
替换脚本,这作为起点是没有用的。
所以这是一个纯粹的 bash 解决方案:
#!/bin/bash
url1=${1:-"http://unix.stackexchange.com/questions/tagged/linux?page=2&sort=newest&pagesize=15"}
url2=${2:-"http://unix.stackexchange.com/questions/tagged/linux?page=34&sort=newest&pagesize=15"}
pagenum=${3:-42}
function splitOnDigit() {
prefix="${1%%[0-9]*}"
url1="${1#$prefix}" # remainder if you strip the prefix
url2="${2#$prefix}"
suffix1="&${1#*&}" # remainder after the number
suffix2="&${2#*&}"
num="${url1%$suffix1}" # the number that we just split around
if [[ $suffix1 == $1 ]]; then
# if substitutions failed, we're at the end
echo "$prefix$3"
return
fi
if [[ $suffix1 == $suffix2 ]]; then
echo "$prefix$3$suffix1"
else
echo -n "$prefix$num"
splitOnDigit "$suffix1" "$suffix2" "$3"
fi
}
splitOnDigit "$url1" "$url2" "$pagenum"
它通过将数字分开来比较两个字符串。只需将其保存在某个地方并运行它 - 它是独立的。递归部分的存在是为了防止更改的数字部分不是第一个像您的示例中那样找到的数字部分。
要生成整个范围的页码,请将整个过程放入循环中(采用三个参数:url1 url2 pagenumber,就像它实现的函数一样)。它的速度足够快,可以按原样工作,但字符串修改只能完成一次,并保存为前缀后缀对,您可以在其中放置迭代数字。