Posortuj listę nazw domen (FQDN), zaczynając od tld i od lewej

20

Chcę posortować listę nazw domen (biała lista filtrów internetowych), zaczynając od TLD i pracując w górę. Szukam dowolnego narzędzia * nix lub Windows, które może to zrobić z łatwością, choć skrypt też byłby w porządku.

Więc jeśli jest to lista, którą otrzymałeś

www.activityvillage.co.uk 
ajax.googleapis.com 
akhet.co.uk 
alchemy.l8r.pl 
au.af.mil 
bbc.co.uk 
bensguide.gpo.gov 
chrome.angrybirds.com 
cms.hss.gov 
crl.godaddy.com 
digitalhistory.uh.edu 
digital.library.okstate.edu 
digital.olivesoftware.com

Właśnie tego chcę jako wynik.

chrome.angrybirds.com 
crl.godaddy.com 
ajax.googleapis.com 
digital.olivesoftware.com 
digital.library.okstate.edu 
digitalhistory.uh.edu 
bensguide.gpo.gov 
cms.hss.gov 
au.af.mil 
alchemy.l8r.pl 
www.activityvillage.co.uk 
akhet.co.uk 
bbc.co.uk

Na wypadek, gdybyś zastanawiał się, dlaczego, Squidguard, ma wadę / błąd w projekcie. Jeśli oba www.example.comi example.comoba umieszczone w wykazie, a następnie example.comwejście jest ignorowany i można odwiedzić tylko zawartość z www.example.com. Mam kilka dużych list, które wymagają uporządkowania, ponieważ ktoś dodał wpisy, nie patrząc najpierw.

Zoredache
źródło
Czy comdomeny nie powinny pojawiać się wcześniej eduna posortowanej liście?
Sven
9
Tak, nie udaje mi się ręcznie sortować, dlatego szukam narzędzia. :)
Zoredache
3
Także wersja Pythona jest ładna w porównaniu z wersją Perla, ponieważ sortowanie pytonów działa na listach list; sortowanie perla nie było i musiało zostać zaimplementowane.
Mark Wagner
1
Na marginesie byłoby to o wiele trudniejsze, gdyby OP poprosił o to, aby najwyższe domeny zgodnie z publiczną sufiksem Mozilli ( publicsuffix.org ) traktować jako jeden blok. W pewnym momencie mógłbym to zrobić (byłoby to miło mieć projekt), ktoś inny zainteresowany?
phk

Odpowiedzi:

15

Ten prosty skrypt Pythona zrobi to, co chcesz. W tym przykładzie nazywam plik domain-sort.py:

#!/usr/bin/env python
from fileinput import input
for y in sorted([x.strip().split('.')[::-1] for x in input()]): print '.'.join(y[::-1])

Aby go uruchomić, użyj:

cat file.txt | ./domain-sort.py

Zauważ, że wygląda to trochę brzydiej, ponieważ napisałem to jako mniej więcej prostą jednowierszową musiałem użyć notacji plastra,[::-1] gdzie działają wartości ujemne, aby utworzyć kopię tej samej listy w odwrotnej kolejności, zamiast używać bardziej deklaratywnych, reverse()które robi to na miejscu w sposób, który przerywa kompozycję.

A oto nieco dłuższa, ale być może bardziej czytelna wersja, która używa, reversed()która zwraca iterator, stąd potrzeba również owinięcia go, list()aby użyć iteratora i utworzyć listę:

#!/usr/bin/env python
from fileinput import input
for y in sorted([list(reversed(x.strip().split('.'))) for x in input()]): print '.'.join(list(reversed(y)))

W przypadku pliku z 1500 losowo posortowanymi liniami zajmuje to około 0,02 sekundy:

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.02
Maximum resident set size (kbytes): 21632

W przypadku pliku z 150 000 losowo posortowanych linii zajmuje to nieco ponad 3 sekundy:

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.20
Maximum resident set size (kbytes): 180128

Tu jest zapewne bardziej czytelna wersja, że robi to reverse()i sort()na miejscu, ale to działa w tym samym czasie, a właściwie zajmuje nieco więcej pamięci.

#!/usr/bin/env python
from fileinput import input

data = []
for x in input():
   d = x.strip().split('.')
   d.reverse()
   data.append(d)
data.sort()
for y in data:
   y.reverse()
   print '.'.join(y)

W przypadku pliku z 1500 losowo posortowanymi liniami zajmuje to około 0,02 sekundy:

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.02
Maximum resident set size (kbytes): 22096

W przypadku pliku z 150 000 losowo posortowanych linii zajmuje to nieco ponad 3 sekundy:

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.08
Maximum resident set size (kbytes): 219152
aculich
źródło
Podobało mi się wiele rozwiązań. Akceptuję odpowiedź opartą na pythonie, głównie dlatego, że używam jej w wielu innych skryptach. Wydaje się, że wszystkie pozostałe odpowiedzi również działają.
Zoredache
1
Jeśli ktoś jest zainteresowany sortowaniem najpierw według nazwy domeny, ignorując TLD, użyjdata.sort(key=lambda x: x[1:])
Calimo
9

Oto skrypt PowerShell, który powinien robić, co chcesz. Zasadniczo rzuca wszystkie TLD do tablicy odwraca każdą TLD, sortuje ją, odwraca z powrotem do oryginalnej kolejności, a następnie zapisuje w innym pliku.

$TLDs = Get-Content .\TLDsToSort-In.txt
$TLDStrings = @();

foreach ($TLD in $TLDs){
    $split = $TLD.split(".")
    [array]::Reverse($split)
    $TLDStrings += ,$split
}

$TLDStrings = $TLDStrings|Sort-Object

foreach ($TLD in $TLDStrings){[array]::Reverse($TLD)}

$TLDStrings | %{[string]::join('.', $_)} | Out-File .\TLDsToSort-Out.txt

Uruchomiłem go na 1500 rekordach - zajęło 5 sekund na dość mocnym pulpicie.

Mark Henderson
źródło
Myślę, że konwersja tego skryptu na bash lub inny język powinna być dość prosta.
Mark Henderson
5 sekund wydaje się długim czasem dla zaledwie 1500 linii. Moja implementacja Pythona robi 1500 w ułamku sekundy i 150 000 w nieco ponad 3 sekundy. Jak myślisz, co powoduje, że jest tak wolny w PowerShell?
aculich
Tak, to dużo czasu. Nie mam pojęcia, dlaczego tak długo to trwa. Prawdopodobnie dlatego, że PowerShell tak naprawdę nie ma na celu robienia takich rzeczy.
Mark Henderson
7

cat domain.txt | rev | sortuj | obrót silnika

użytkownik3721740
źródło
Myślę, że to zadziała. Lubię jednak sortować TLD i to by tego nie osiągnęło. Korzystając z tego, TLD w moim przykładzie byłyby w kolejności (uk, mil, pl, com, edu, gov) Ponieważ jest to proste sortowanie od prawej do lewej, zamiast granic domen.
Zoredache
najlepsza odpowiedź, jaką widziałem!
Daniel
1
rev domain.txt|sort|rev
Bogaty
6

Nieco mniej tajemniczy, a przynajmniej ładniejszy Perl:

use warnings;
use strict;

my @lines = <>;
chomp @lines;

@lines =
    map { join ".", reverse split /\./ }
    sort
    map { join ".", reverse split /\./ }
    @lines;

print "$_\n" for @lines;

Jest to prosty przykład transformacji Guttmana – Roslera : konwertujemy linie do odpowiedniej formy do sortowania (tutaj dzielimy nazwę domeny na kropki i odwracamy kolejność części), sortujemy je przy użyciu rodzimego sortowania leksykograficznego, a następnie konwertujemy wiersze z powrotem do oryginalnej postaci.

Ilmari Karonen
źródło
6

W skryptach uniksowych: odwróć, sortuj i odwróć:

awk -F "." '{for(i=NF; i > 1; i--) printf "%s.", $i; print $1}' file |
  sort |
  awk -F "." '{for(i=NF; i > 1; i--) printf "%s.", $i; print $1}'
jfg956
źródło
Podobnie rzecz ma się z pojedynczą pętlą: awk -F. '{for(i=NF;i>0;i--){printf ".%s",$i};printf "\t%s\n",$0}' file|sort|cut -f2może najpierw zechcesz rozebrać lokalnych hostówgrep \. file | awk ...
Rich
3

Oto on (krótki i tajemniczy) perl:

#!/usr/bin/perl -w
@d = <>; chomp @d;
for (@d) { $rd{$_} = [ reverse split /\./ ] }
for $d (sort { for $i (0..$#{$rd{$a}}) {
        $i > $#{$rd{$b}} and return 1;
        $rd{$a}[$i] cmp $rd{$b}[$i] or next;
        return $rd{$a}[$i] cmp $rd{$b}[$i];
} } @d) { print "$d\n" }
Mark Wagner
źródło
Czy masz informacje o czasie dla tego rodzaju? Jestem ciekawy, jak to się ma do implementacji PowerShell @ Mark-Henderson , a także mojej implementacji Python . Użyłem /usr/bin/time -vstatystyk czasu, który upłynął, i maksymalnej pamięci.
aculich
4
Perl całkowicie WYGRYWA w zaciemnieniu.
Massimo
4
Opisanie skryptu Perla jako „krótkiego i tajemniczego” jest zbędne.
Belmin Fernandez
@aculich, z wyjątkiem skryptu PowerShell, wszystkie opcje wydają się zajmować mniej niż 0,1 sekundy w moim pliku.
Zoredache
0
awk -F"." 's="";{for(i=NF;i>0;i--) {if (i<NF) s=s "." $i; else s=$i}; print s}' <<<filename>>> | sort | awk -F"." 's="";{for(i=NF;i>0;i--) {if (i<NF) s=s "." $i; else s=$i}; print s}'

Powoduje to odwrócenie każdego pola w nazwie domeny, sortowanie i cofanie.

To naprawdę sortuje listę domen, leksykograficznie na podstawie każdej części nazwy domeny, od prawej do lewej.

Rozwiązanie odwrotne ( rev <<<filename>>> | sort | rev) nie, próbowałem.

Mike Rudra
źródło