Aşağıdakiler, Kabarcık sıralaması yapacak bir komut dosyası oluşturması anlamında Jeff'in cevabındaki bir varyasyondur sed
, ancak kendi cevabını garanti etmek için yeterince farklıdır.
Fark, O (n ^ 2) temel normal ifadeleri üretmek yerine, O (n) genişletilmiş düzenli ifadeler üretmesidir. Ortaya çıkan komut dosyası yaklaşık 15 KB büyüklüğünde olacaktır. sed
Komut dosyasının çalışma süresi bir saniyenin kesiridir (komut dosyasının oluşturulması biraz daha uzun sürer).
Noktalarla sınırlandırılmış pozitif tam sayıları sıralamakla sınırlıdır, ancak tam sayıların boyutu (sadece 255
ana döngüde artış ) veya tam sayıların sayısı ile sınırlı değildir . Sınırlayıcı delim='.'
, kod değiştirilerek değiştirilebilir .
Düzenli ifadeleri düzeltmek için kafam bitti, bu yüzden başka bir günün detaylarını açıklayacağım.
#!/bin/bash
# This function creates a extended regular expression
# that matches a positive number less than the given parameter.
lt_pattern() {
local n="$1" # Our number.
local -a res # Our result, an array of regular expressions that we
# later join into a string.
for (( i = 1; i < ${#n}; ++i )); do
d=$(( ${n: -i:1} - 1 )) # The i:th digit of the number, from right to left, minus one.
if (( d >= 0 )); then
res+=( "$( printf '%d[0-%d][0-9]{%d}' "${n:0:-i}" "$d" "$(( i - 1 ))" )" )
fi
done
d=${n:0:1} # The first digit of the number.
if (( d > 1 )); then
res+=( "$( printf '[1-%d][0-9]{%d}' "$(( d - 1 ))" "$(( ${#n} - 1 ))" )" )
fi
if (( n > 9 )); then
# The number is 10 or larger.
res+=( "$( printf '[0-9]{1,%d}' "$(( ${#n} - 1 ))" )" )
fi
if (( n == 1 )); then
# The number is 1. The only thing smaller is zero.
res+=( 0 )
fi
# Join our res array of expressions into a '|'-delimited string.
( IFS='|'; printf '%s\n' "${res[*]}" )
}
echo ':top'
delim='.'
for (( n = 255; n > 0; --n )); do
printf 's/\\<%d\\>\\%s\\<(%s)\\>/\\1%s%d/g\n' \
"$n" "$delim" "$( lt_pattern "$n" )" "$delim" "$n"
done
echo 'ttop'
Komut dosyası şöyle görünecektir:
$ bash generator.sh >script.sed
$ head -n 5 script.sed
:top
s/\<255\>\.\<(25[0-4][0-9]{0}|2[0-4][0-9]{1}|[1-1][0-9]{2}|[0-9]{1,2})\>/\1.255/g
s/\<254\>\.\<(25[0-3][0-9]{0}|2[0-4][0-9]{1}|[1-1][0-9]{2}|[0-9]{1,2})\>/\1.254/g
s/\<253\>\.\<(25[0-2][0-9]{0}|2[0-4][0-9]{1}|[1-1][0-9]{2}|[0-9]{1,2})\>/\1.253/g
s/\<252\>\.\<(25[0-1][0-9]{0}|2[0-4][0-9]{1}|[1-1][0-9]{2}|[0-9]{1,2})\>/\1.252/g
$ tail -n 5 script.sed
s/\<4\>\.\<([1-3][0-9]{0})\>/\1.4/g
s/\<3\>\.\<([1-2][0-9]{0})\>/\1.3/g
s/\<2\>\.\<([1-1][0-9]{0})\>/\1.2/g
s/\<1\>\.\<(0)\>/\1.1/g
ttop
Oluşturulan normal ifadelerin ardındaki fikir, her tamsayıdan daha küçük sayılar için eşleme oluşturmaktır; bu iki sayı bozuk olur ve bu şekilde değiştirilir. Normal ifadeler birkaç VEYA seçeneğinde gruplanır. Her bir öğeye eklenen aralıklara çok dikkat edin, bazen öyledir {0}
, yani hemen önceki öğenin aramadan çıkarılması gerekir. Soldan sağa regex seçenekleri, verilen sayıdan daha küçük olan sayıları şu şekilde eşleştirir:
- olanlar yer
- onlarca yer
- yüzlerce yer
- (büyük sayılar için gerektiğinde devam eder)
- veya daha küçük (basamak sayısı) olarak
Bir örneği hecelemek için, 101
(okunabilirlik için ek alanlarla birlikte):
s/ \<101\> \. \<(10[0-0][0-9]{0} | [0-9]{1,2})\> / \1.101 /g
Burada, ilk alternatif 100'den 100'e kadar olan sayılara izin verir; ikinci alternatif, 0 ila 99 arasında bir değere izin verir.
Başka bir örnek 154
:
s/ \<154\> \. \<(15[0-3][0-9]{0} | 1[0-4][0-9]{1} | [0-9]{1,2})\> / \1.154 /g
Burada ilk seçenek 150 ila 153; ikincisi 100 ila 149'a izin verir ve sonuncusu 0 ila 99'a izin verir.
Bir döngüde dört kez test etme:
for test_run in {1..4}; do
nums=$(( RANDOM%256 )).$(( RANDOM%256 )).$(( RANDOM%256 )).$(( RANDOM%256 ))
printf 'nums=%s\n' "$nums"
sed -E -f script.sed <<<"$nums"
done
Çıktı:
nums=90.19.146.232
19.90.146.232
nums=8.226.70.154
8.70.154.226
nums=1.64.96.143
1.64.96.143
nums=67.6.203.56
6.56.67.203