
リンクを考える
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
ここでは「ページ」が増加します。ページが115ページの場合、最後のページのページ値は115になります。
2つのサンプルリンクを処理して、リンクのどの部分が増加するかをどうやって知ることができますか?
シェルスクリプトを使用して115個のリンクをすべて作成する必要があります。
入力は、2ページと3ページへの2つのリンクと合計ページ数です。
私はbashシェルを使用していますが、Pythonも使用できます。
答え1
^
これは、Perlのビット排他的OR(XOR)演算子()の使用方法を示すPerlスクリプトです。
スクリプト
私はそれを呼ぶ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
次のような出力が生成されます。メモ:これらの文字は印刷できず、16進値です。 0x00はNULL文字の16進値で、0x01は1です。
...
[] is 0x00
[] is 0x00
[] is 0x00
[] is 0x00
[] is 0x00
[ ] is 0x01
[] is 0x00
[] is 0x00
...
ゼロ以外の値が異なる値を表すときに返される値。他の例:
$ 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
null()ではなく文字に対してのみループを回すことです。したがって、あなたの例では実際に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] は、最後に成功したマッチ開始のオフセットです。
この一致はループの制御部分で発生し、null文字()以外の文字を探して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]
、最初の2つのトリプルを使用してページ番号の周りに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"
数字を区切って2つの文字列を比較します。どこかに保存して実行するだけです。それ自体が含まれています。数値の変更された部分が例のように見つかった最初の部分ではない場合、再帰部分が存在します。
フルスコープのページ番号を生成するには、プロセス全体をループに入れます(実装されている関数と同様に、url1 url2 pagenumberの3つのパラメータを使用します)。現状のまま動作するほど高速ですが、文字列の変更は一度だけ行われ、繰り返し数字を入力するプレフィックスとサフィックスのペアとして保存されます。