Как удалить дубликаты доменов из большого списка URL-адресов? RegEx или В противном случае - PullRequest
3 голосов
/ 23 октября 2010

Первоначально я задавал этот вопрос: Регулярное выражение в gVim для удаления дублирующихся доменов из списка

Тем не менее, я понимаю, что, скорее всего, найду работающее решение, если я "расширю свои возможности" с точки зрения того, какое решение я готов принять.

Итак, я перефразирую свой вопрос и, возможно, я найду лучшее решение ... вот так:

У меня большой список URL-адресов в файле .txt (я использую 32-разрядную версию Windows Vista), и мне нужно удалить дубликаты ДОМЕНОВ (и весь соответствующий URL-адрес для каждого дубликата), оставив после первого появления каждого домена , В этом конкретном файле примерно 6 000 000 URL-адресов в следующем формате (очевидно, что в URL-адресах нет пробела, я просто должен был это сделать, потому что у меня недостаточно сообщений для публикации такого количества «живых» URL-адресов). ):

http://www.exampleurl.com/something.php
http://exampleurl.com/somethingelse.htm  
http://exampleurl2.com/another-url  
http://www.exampleurl2.com/a-url.htm  
http://exampleurl2.com/yet-another-url.html  
http://exampleurl.com/  
http://www.exampleurl3.com/here_is_a_url  
http://www.exampleurl5.com/something

Каким бы ни было решение, выходной файл, использующий в качестве входных данных выше, должен быть таким:

http://www.exampleurl.com/something.php  
http://exampleurl2.com/another-url  
http://www.exampleurl3.com/here_is_a_url  
http://www.exampleurl5.com/something

Вы заметили, что сейчас нет повторяющихся доменов, и он оставил позади первое вхождение, с которым столкнулся.

Если кто-нибудь может мне помочь, будь то использование регулярных выражений или какая-то программа, о которой я не знаю, это было бы здорово.

Я скажу это, хотя, у меня НЕТ опыта использования чего-либо, кроме ОС Windows, поэтому решение, влекущее за собой что-то, кроме программы Windows, потребовало бы, так сказать, небольшого «детского шага» (если кто-то достаточно добр для этого).

Ответы [ 4 ]

2 голосов
/ 23 октября 2010

Регулярные выражения в Python, очень сырые и не работают с поддоменами.Основная концепция заключается в использовании словарных ключей и значений, ключом будет имя домена, а значение будет перезаписано, если ключ уже существует.

import re

pattern = re.compile(r'(http://?)(w*)(\.*)(\w*)(\.)(\w*)')
urlsFile = open("urlsin.txt", "r")
outFile = open("outurls.txt", "w")
urlsDict = {}

for linein in urlsFile.readlines():
    match = pattern.search(linein)
    url = match.groups()
    domain = url[3]
    urlsDict[domain] = linein

outFile.write("".join(urlsDict.values()))

urlsFile.close()
outFile.close()

Вы можете расширить его для фильтрации поддоменов, но основная идеяесть ли я думаюИ для 6 миллионов URL-адресов в Python может потребоваться некоторое время ...

Некоторые люди, сталкиваясь с проблемой, думают: «Я знаю, я буду использовать регулярные выражения».Теперь у них две проблемы.- Джейми Завински, в comp.emacs.xemacs

1 голос
/ 23 октября 2010

Я бы использовал комбинацию Perl и регулярных выражений. Моя первая версия я

   use warnings ;
   use strict ;
   my %seen ;
   while (<>) {
       if ( m{ // ( .*? ) / }x ) {
       my $dom = $1 ;

       print unless $seen {$dom} ++ ;
       print "$dom\n" ;
     } else {
       print "Unrecognised line: $_" ;
     }
   }

Но это относится к www.exampleurl.com и exampleurl.com как к разным. Моя вторая версия имеет

if ( m{ // (?:www\.)? ( .*? ) / }x )

который игнорирует "www." на фронте. Возможно, вы могли бы немного улучшить регулярное выражение, но это оставлено читателю.

Наконец, вы могли бы немного прокомментировать регулярное выражение (это позволяет квалификатор /x). Скорее, это зависит от того, кто будет это читать, - это можно считать слишком многословным.

           if ( m{
               //          # match double slash
               (?:www\.)?  # ignore www
               (           # start capture
                  .*?      # anything but not greedy
                )          # end capture
                /          # match /
               }x ) {

Я использую m{} вместо //, чтобы избежать /\/\/

1 голос
/ 23 октября 2010

Для этой конкретной ситуации я бы не использовал Regex. URL-адреса - это четко определенный формат, и в BCL существует простой в использовании анализатор для этого формата: тип Uri Его можно использовать для простого анализа типа и получения информации о домене, которую вы ищете.

Вот краткий пример

public List<string> GetUrlWithUniqueDomain(string file) {
  using ( var reader = new StreamReader(file) ) {
    var list = new List<string>();
    var found = new HashSet<string>();
    var line = reader.ReadLine();
    while (line != null) {
      Uri uri;
      if ( Uri.TryCreate(line, UriKind.Absolute, out uri) && found.Add(uri.Host)) {
        list.Add(line);
      }
      line = reader.ReadLine();
    }
  }
  return list;
}
0 голосов
/ 23 октября 2010
  1. Найдите поле Unix, если у вас его нет, или получите Cygwin
  2. , используйте tr для преобразования '.'в TAB для удобства.
  3. используйте sort (1) для сортировки строк по части имени домена.Это можно сделать немного проще, написав awk-программу для нормализации www-части.

И да, у вас есть все вместеВозможно, используйте uniq (1) для поиска дубликатов.

(Дополнительный кредит: почему бы не сделать это с помощью регулярного выражения?

...