Сортировать список доменных имен (FQDN), начиная с tld и работая слева

20

Я ищу, чтобы отсортировать список доменных имен (белый список веб-фильтров), начиная с TLD и работая вверх. Я ищу любые инструменты * nix или windows, которые могут сделать это легко, хотя сценарий тоже подойдет.

Так что, если список вам дан

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

Это то, что я хочу в качестве вывода.

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

На тот случай, если вам интересно, почему у Squidguard есть ошибка в дизайне. Если оба www.example.comи example.comоба включены в список, то example.comзапись игнорируется, и вы можете просматривать только контент из www.example.com. У меня есть несколько больших списков, которые нуждаются в некоторой очистке, потому что кто-то добавил записи без предварительного просмотра.

Zoredache
источник
Разве comдомены не должны появляться раньше eduв вашем отсортированном списке?
Свен
9
Да, у меня не получается выполнить ручную сортировку, поэтому я ищу инструмент. :)
Zoredache
3
Кроме того, версия на python хороша по сравнению с версией на perl, потому что сортировка pythons работает со списками списков; Сортировка perl не требует и должна быть реализована.
Марк Вагнер
1
С другой стороны, это было бы намного сложнее, если бы OP попросил, чтобы верхние домены в соответствии с открытым списком суффиксов Mozilla ( publicsuffix.org ) обрабатывались как один блок. В какой-то момент я мог бы заняться этим (было бы неплохо иметь проект), кому-то еще интересно?
PhK

Ответы:

15

Этот простой скрипт на Python сделает то, что вы хотите. В этом примере я называю файл 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])

Для запуска используйте:

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

Обратите внимание , что это выглядит немного уродливее , так как я написал это как более или менее простой один лайнер я должен был использовать ломтик обозначение[::-1] , где работают отрицательные значения , чтобы сделать копию одного и тот же список в обратном порядке , вместо того , чтобы использовать более декларативный , reverse()который делает это на месте таким образом, что нарушает компоновку.

А вот немного более длинная, но, возможно, более читаемая версия, в reversed()которой используется итератор, поэтому необходимо также обернуть его, 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)))

Для файла с 1500 случайно отсортированными строками это занимает ~ 0,02 секунды:

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

Для файла с 150000 случайно отсортированных строк это занимает чуть более 3 секунд:

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

Вот, пожалуй, более читаемая версия, которая выполняет операции «на месте» reverse()и « sort()на месте», но работает за то же время и фактически занимает немного больше памяти.

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

Для файла с 1500 случайно отсортированными строками это занимает ~ 0,02 секунды:

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

Для файла с 150000 случайно отсортированных строк это занимает чуть более 3 секунд:

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.08
Maximum resident set size (kbytes): 219152
aculich
источник
Мне понравилось видеть много решений. Я принимаю основанный на Python ответ в основном потому, что это то, что я использую для многих других моих сценариев. Другие ответы, кажется, тоже работают.
Zoredache
1
Если кто-то заинтересован в сортировке по имени домена в первую очередь, игнорируя TLD, используйтеdata.sort(key=lambda x: x[1:])
Calimo
9

Вот сценарий PowerShell, который должен делать то, что вы хотите. По сути, он выбрасывает все TLD в массив, переворачивает каждый TLD, сортирует его, возвращает его в исходный порядок, а затем сохраняет в другом файле.

$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

Запустил его на 1500 записях - заняло 5 секунд на достаточно мощном рабочем столе.

Марк Хендерсон
источник
Я думаю, что конвертировать этот скрипт в bash или другой язык должно быть довольно просто.
Марк Хендерсон
5 секунд кажутся долгим временем только для 1500 строк. Моя реализация на python делает 1500 за долю секунды и 150 000 всего за 3 секунды. Как вы думаете, что делает так медленно в PowerShell?
aculich
Да, это долго. Я понятия не имею, почему это так долго. Возможно, потому что powershell на самом деле не нацелен на такие вещи.
Марк Хендерсон
7

кошка domain.txt | рев | сортировать | оборот

user3721740
источник
Я думаю, это будет работать. Мне действительно нравится сортировка TLD, но это не поможет. Используя это, TLD в моем примере будут иметь следующий порядок (uk, mil, pl, com, edu, gov), поскольку это простая сортировка справа налево вместо границ домена.
Зоредаче
лучший ответ, который я видел!
Даниэль
1
rev domain.txt|sort|rev
Богатое
6

Чуть менее загадочный или, по крайней мере, более красивый Perl:

use warnings;
use strict;

my @lines = <>;
chomp @lines;

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

print "$_\n" for @lines;

Это простой пример преобразования Гутмана – Рослера : мы преобразуем строки в соответствующую сортируемую форму (здесь, разбиваем доменное имя по периодам и меняем порядок частей), сортируем их, используя собственную лексикографическую сортировку, а затем преобразуем линии обратно в исходную форму.

Илмари Каронен
источник
6

В сценариях Unix: обратный, сортировка и обратный:

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
источник
То же самое с одним циклом: awk -F. '{for(i=NF;i>0;i--){printf ".%s",$i};printf "\t%s\n",$0}' file|sort|cut -f2возможно, сначала нужно удалить локальных хостовgrep \. file | awk ...
Rich
3

Вот он (короткий и загадочный) 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" }
Марк Вагнер
источник
У вас есть информация о времени для такого рода? Мне любопытно посмотреть, как это сравнивается с реализацией PowerShell @ Mark-Henderson , а также с моей реализацией Python . Я использовал /usr/bin/time -vдля прошедшего времени и максимальную статистику памяти.
aculich
4
Perl полностью выигрывает при запутывании.
Массимо
4
Описание сценария Perl как «короткого и загадочного» является излишним.
Бельмин Фернандес
@aculich, за исключением сценария powershell, все параметры в моем файле занимают менее 0,1 секунды.
Зоредаче
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}'

То, что это делает, это переворачивает каждое поле в имени домена, сортирует и переворачивает обратно.

Это действительно сортирует список доменов, лексикографически основанный на каждой части имени домена, справа налево.

Обратного решения ( rev <<<filename>>> | sort | rev) нет, я пробовал.

Майк Рудра
источник