Classifique uma lista de nomes de domínio (FQDNs) iniciando em tld e trabalhando à esquerda

20

Estou procurando classificar uma lista de nomes de domínio (uma lista de permissões de filtro da Web) começando no TLD e trabalhando para cima. Estou procurando qualquer ferramenta * nix ou windows que possa fazer isso facilmente, embora um script também esteja bom.

Então, se esta é a lista que você recebe

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

É isso que eu quero como saída.

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

Caso você esteja se perguntando por que, Squidguard, tem uma falha de design / bug. Se ambos www.example.come ambos example.comestiverem incluídos em uma lista, a example.comentrada será ignorada e você poderá acessar apenas o conteúdo de www.example.com. Eu tenho várias listas grandes que precisam de limpeza porque alguém adicionou entradas sem olhar primeiro.

Zoredache
fonte
Os comdomínios não deveriam aparecer antes eduna sua lista classificada?
Sven
9
Sim, falhei na classificação manual, e é por isso que estou procurando uma ferramenta. :)
Zoredache
3
Além disso, a versão python é boa em comparação com a versão perl porque a classificação de pythons funciona em listas de listas; o tipo de perl não e teve que ser implementado.
21812 Mark Wagner
1
Em uma nota lateral, isso seria muito mais desafiador se o OP tivesse solicitado que os principais domínios de acordo com a lista de sufixos públicos da Mozilla ( publicsuffix.org ) fossem tratados como um bloco. Eu poderia, em algum momento, fazer isso (seria bom para um projeto), alguém mais interessado?
Php

Respostas:

15

Este script python simples fará o que você deseja. Neste exemplo, nomeio o arquivo 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])

Para executá-lo, use:

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

Observe que isso parece um pouco mais feio, porque eu escrevi isso como uma linha simples, mais ou menos simples. Eu tive que usar a notação de fatia de[::-1] onde valores negativos funcionam para fazer uma cópia da mesma lista na ordem inversa, em vez de usar o mais declarativo reverse()que fá-lo no lugar de uma maneira que quebre a composição.

E aqui está uma versão um pouco mais longa, mas talvez mais legível que usa o reversed()que retorna um iterador, daí a necessidade de envolvê-lo list()para consumir o iterador e produzir uma lista:

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

Em um arquivo com 1.500 linhas classificadas aleatoriamente, leva ~ 0,02 segundos:

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

Em um arquivo com 150.000 linhas classificadas aleatoriamente, leva um pouco mais de 3 segundos:

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

Aqui está uma versão discutivelmente mais legível que funciona reverse()e sort()no local, mas é executada na mesma quantidade de tempo e, na verdade, requer um pouco mais de memória.

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

Em um arquivo com 1.500 linhas classificadas aleatoriamente, leva ~ 0,02 segundos:

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

Em um arquivo com 150.000 linhas classificadas aleatoriamente, leva um pouco mais de 3 segundos:

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.08
Maximum resident set size (kbytes): 219152
aculich
fonte
Eu gostei de ver muitas soluções. Estou aceitando a resposta baseada em python principalmente porque é o que eu uso para muitos dos meus outros scripts. As outras respostas parecem funcionar também.
Zoredache
1
Se alguém estiver interessado em classificar primeiro o nome de domínio, ignorando o TLD, usedata.sort(key=lambda x: x[1:])
Calimo 07/12/16
9

Aqui está um script do PowerShell que deve fazer o que você deseja. Basicamente, ele lança todos os TLDs em uma matriz, inverte cada TLD, classifica-o, inverte-o de volta à sua ordem original e o salva em outro arquivo.

$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

Executou 1.500 registros - levou 5 segundos em um desktop razoavelmente poderoso.

Mark Henderson
fonte
Deve ser bastante simples converter esse script em bash ou em outro idioma, eu acho.
Mark Henderson
5 segundos parece muito tempo para apenas 1.500 linhas. Minha implementação python faz 1.500 em uma fração de segundo e 150.000 em pouco mais de 3 segundos. O que você acha que o torna tão lento no PowerShell?
Aculich 28/02/12
Sim, faz muito tempo. Eu não tenho idéia por que leva tanto tempo embora. Provavelmente porque o PowerShell não é realmente destinado a fazer coisas assim.
Mark Henderson
7

gato domain.txt | rev | classificar | rev

user3721740
fonte
Eu acho que isso funcionaria. Porém, eu gosto de ter o TLD classificado, e isso não faria isso. Usando isso, os TLDs no meu exemplo estariam na ordem (uk, mil, pl, com, edu, gov). Como é uma classificação simples da direita para a esquerda, em vez dos limites do domínio.
Zoredache
melhor resposta que eu já vi!
Daniel
1
rev domain.txt|sort|rev
Rico
6

Um pouco menos enigmático, ou pelo menos mais bonito, Perl:

use warnings;
use strict;

my @lines = <>;
chomp @lines;

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

print "$_\n" for @lines;

Este é um exemplo simples de uma transformação de Guttman-Rosler : convertemos as linhas no formato classificável apropriado (aqui, dividimos o nome do domínio em períodos e invertemos a ordem das partes), classificá-las usando a classificação lexicográfica nativa e depois convertemos o linhas de volta à sua forma original.

Ilmari Karonen
fonte
6

Nos scripts Unix: reverse, sort e reverse:

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
fonte
Coisa semelhante com um único loop: awk -F. '{for(i=NF;i>0;i--){printf ".%s",$i};printf "\t%s\n",$0}' file|sort|cut -f2Pode querer retirar anfitriões locais primeiro comgrep \. file | awk ...
rico
3

Aqui está o perl (curto e enigmático):

#!/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
fonte
Você tem informações de tempo para esse tipo? Estou curioso para ver como isso se compara à implementação do PowerShell de @ Mark-Henderson , bem como à minha implementação em Python . Eu usei /usr/bin/time -vo tempo decorrido e as estatísticas máximas de memória.
28612 aculich
4
Perl totalmente vence na ofuscação.
Massimo
4
A descrição de um script Perl como "curto e enigmático" é redundante.
Belmin Fernandez 28/02/12
@aculich, com exceção do script do PowerShell, todas as opções parecem levar menos de 0,1 segundos no meu arquivo.
precisa
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}'

O que isso faz é reverter cada arquivo no nome de domínio, classificar e retroceder.

Isso realmente classifica a lista de domínios, lexicograficamente com base em cada parte do nome do domínio, da direita para a esquerda.

A solução reversa ( rev <<<filename>>> | sort | rev), não, eu tentei.

Mike Rudra
fonte