生成带有递增变量的页面链接

lim*_*ala 6 shell grep shell-script wget

考虑链接

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 也是可能的

slm*_*slm 5

这是一个 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";
}
Run Code Online (Sandbox Code Playgroud)

细节

该脚本的独特之处在于使用了 Perl 的 ( ^) 运算符。这种方法的强大之处在于以下代码片段:

my $mask = $s1 ^ $s2;
while ($mask =~ /[^\0]/g) {
  $posOfDiff = $-[0];
}
Run Code Online (Sandbox Code Playgroud)

以上将$mask使用 2 个字符串创建一个掩码 ( )。一个XOR掩码是将包含一个0值的向量之间的是匹配$s1$s2,和一个1,其中它们之间的区别。如果你想说服自己,你可以添加这行代码:

my $mask = $s1 ^ $s2;
printf "[$_] is 0x%02x\n", ord($_) for split //, $mask;
Run Code Online (Sandbox Code Playgroud)

面具的内脏

printf将产生这样的输出。注意:字符是不可打印的,它们是十六进制值。0x00 是空字符的十六进制值,0x01 是 1。

...
[] is 0x00
[] is 0x00
[] is 0x00
[] is 0x00
[] is 0x00
[ ] is 0x01
[] is 0x00
[] is 0x00
...
Run Code Online (Sandbox Code Playgroud)

当任何非 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
Run Code Online (Sandbox Code Playgroud)

循环通过面具

while循环的另一个有趣的特性是它只循环遍历$mask非空字符( \0)。因此,在您的示例中,我们实际上只执行了 1 次 while 循环,因为 2 个字符串之间只有 1 个差异。如果有 2 个差异,它将执行 2 次。所以这是一个相当有效的方法来做到这一点。

如果您需要更令人信服,这里有一些额外的代码行,您可以添加这些代码以显示while循环:

while ($mask =~ /[^\0]/g) {
  print "in the loop\n";
  print "what we're looking for:" . $-[0] . "\n";
Run Code Online (Sandbox Code Playgroud)

这些行只显示一次:

in the loop
what we're looking for:58
Run Code Online (Sandbox Code Playgroud)

保存差异位置

一旦找到匹配项,while 循环的主体将执行并且位置将被记录在变量中$posOfDiff。如何?这里的美妙之处在于使用了变量 $-[0]。这将为我们提供最后一次成功匹配的位置的偏移量。

$-[0] 是最后一次成功匹配开始的偏移量。

这个匹配是在while循环的控制部分发生的,我们正在寻找$mask不是空字符 ( \0) 的字符,因此我们的差异字符:

$mask =~ /[^\0]/g
Run Code Online (Sandbox Code Playgroud)

注意:结尾g告诉 Perl 中的 match 函数在全局范围内执行此操作,因此它将继续查找匹配项,直到用尽字符串$mask.

还有什么?

这个脚本的其余部分几乎是 Perl 的样板,不值得进一步讨论。

参考


Tho*_*man 3

在Python中你可以使用SequenceMatcherfrom 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
Run Code Online (Sandbox Code Playgroud)

SequenceMatcher.get_matching_blocks()将返回形式为 的三元组列表(i, j, n),其中a[i:i+n] == b[j:j+n]. 使用前两个这样的三元组,我们构建了围绕页码的 URL 的前缀和后缀,并迭代 URL 的范围。