Trier une liste de noms de domaine (FQDN) en commençant par tld et en travaillant à gauche

20

Je cherche à trier une liste de noms de domaine (une liste blanche de filtres Web) à partir du TLD et en remontant. Je recherche des outils * nix ou windows qui peuvent le faire facilement, même si un script conviendrait également.

Donc, si c'est la liste qui vous est donné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

C'est ce que je veux comme sortie.

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

Juste au cas où vous vous demandez pourquoi Squidguard a un défaut de conception / bug. Si les deux www.example.comet example.comsont tous deux inclus dans une liste, l' example.comentrée est ignorée et vous ne pouvez visiter que le contenu de www.example.com. J'ai plusieurs grandes listes qui nécessitent un nettoyage, car quelqu'un a ajouté des entrées sans regarder en premier.

Zoredache
la source
Les comdomaines ne devraient-ils pas apparaître avant edudans votre liste triée?
Sven
9
Ouais, j'échoue au tri manuel, c'est pourquoi je recherche un outil. :)
Zoredache
3
De plus, la version python y est agréable par rapport à la version perl car le tri de pythons fonctionne sur des listes de listes; le tri de perl ne le fait pas et devait être implémenté.
Mark Wagner
1
D'un autre côté, cela serait beaucoup plus difficile si OP avait demandé que les principaux domaines selon la liste des suffixes publics de Mozilla ( publicsuffix.org ) soient traités comme un seul bloc. À un moment donné, je pourrais peut-être le faire (ce serait bien d'avoir un projet), quelqu'un d'autre est-il intéressé?
phk

Réponses:

15

Ce simple script python fera ce que vous voulez. Dans cet exemple, je nomme le fichier 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])

Pour l'exécuter, utilisez:

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

Notez que cela semble un peu plus laid depuis que j'ai écrit cela comme plus ou moins un simple simple, j'ai dû utiliser la notation par tranche d'[::-1]les valeurs négatives fonctionnent pour faire une copie de la même liste dans l'ordre inverse au lieu d'utiliser le plus déclaratif reverse()qui le fait en place d'une manière qui rompt la composabilité.

Et voici une version légèrement plus longue, mais peut-être plus lisible qui utilise reversed()qui retourne un itérateur, d'où la nécessité de l'envelopper également list()pour consommer l'itérateur et produire une liste:

#!/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)))

Sur un fichier avec 1 500 lignes triées aléatoirement, cela prend ~ 0,02 seconde:

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

Sur un fichier avec 150 000 lignes triées aléatoirement, cela prend un peu plus de 3 secondes:

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

Voici une version sans doute plus lisible qui fait le reverse()et sort()en place, mais elle s'exécute dans le même temps et prend en fait un peu plus de mémoire.

#!/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)

Sur un fichier avec 1 500 lignes triées aléatoirement, cela prend ~ 0,02 seconde:

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

Sur un fichier avec 150 000 lignes triées aléatoirement, cela prend un peu plus de 3 secondes:

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.08
Maximum resident set size (kbytes): 219152
aculich
la source
J'ai aimé voir beaucoup de solutions. J'accepte la réponse basée sur python principalement parce que c'est ce que j'utilise pour beaucoup de mes autres scripts. Les autres réponses semblent toutes fonctionner également.
Zoredache
1
Si quelqu'un souhaite d'abord trier par nom de domaine, en ignorant le TLD, utilisezdata.sort(key=lambda x: x[1:])
Calimo
9

Voici un script PowerShell qui devrait faire ce que vous voulez. Fondamentalement, il jette tous les TLD dans un tableau inverse chaque TLD, le trie, le ramène à son ordre d'origine, puis l'enregistre dans un autre fichier.

$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

Il a fonctionné sur 1 500 enregistrements - a pris 5 secondes sur un bureau raisonnablement puissant.

Mark Henderson
la source
Il devrait être assez simple de convertir ce script en bash ou dans une autre langue, je pense.
Mark Henderson
5 secondes semble être long pour seulement 1 500 lignes. Mon implémentation python fait 1 500 en une fraction de seconde et 150 000 en un peu plus de 3 secondes. Selon vous, qu'est-ce qui le rend si lent dans PowerShell?
aculich
Oui, c'est long. Je ne sais pas pourquoi cela prend si longtemps. Probablement parce que PowerShell n'est pas vraiment destiné à faire des choses comme ça.
Mark Henderson
7

cat domain.txt | rev | trier | tour

user3721740
la source
Je suppose que cela fonctionnerait. J'aime bien que le TLD soit trié, et cela ne permettrait pas de le faire. En utilisant cela, les TLD dans mon exemple seraient dans l'ordre (uk, mil, pl, com, edu, gov), car il s'agit d'un simple tri de droite à gauche, au lieu des limites de domaine.
Zoredache
meilleure réponse que j'ai vue!
Daniel
1
rev domain.txt|sort|rev
Rich
6

Perl légèrement moins crypté, ou du moins plus joli:

use warnings;
use strict;

my @lines = <>;
chomp @lines;

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

print "$_\n" for @lines;

Voici un exemple simple de transformation de Guttman – Rosler : nous convertissons les lignes dans la forme triable appropriée (ici, divisons le nom de domaine par périodes et inversons l'ordre des parties), trions-les en utilisant le tri lexicographique natif, puis convertissons le lignes à leur forme d'origine.

Ilmari Karonen
la source
6

Dans les scripts Unix: inversez, triez et inversez:

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
la source
Similaire avec une seule boucle: awk -F. '{for(i=NF;i>0;i--){printf ".%s",$i};printf "\t%s\n",$0}' file|sort|cut -f2pourrait vouloir d'abord éliminer les hôtes locaux avecgrep \. file | awk ...
Rich
3

Le voici en (court et cryptique) 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
la source
Avez-vous des informations de synchronisation pour ce type? Je suis curieux de voir comment cela se compare à l'implémentation PowerShell de @ Mark-Henderson , ainsi qu'à mon implémentation Python . J'ai utilisé /usr/bin/time -vle temps écoulé et les statistiques de mémoire max.
aculich
4
Perl gagne totalement à l'obscurcissement.
Massimo
4
Décrire un script Perl comme "court et cryptique" est redondant.
Belmin Fernandez
@aculich, à l'exception du script powershell, toutes les options semblent prendre moins de 0,1 seconde sur mon fichier.
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}'

Cela revient à inverser chaque fichier du nom de domaine, à trier et à inverser.

Cela trie vraiment la liste des domaines, lexicographiquement en fonction de chaque partie du nom de domaine, de droite à gauche.

La solution inverse ( rev <<<filename>>> | sort | rev), non, je l'ai essayée.

Mike Rudra
la source