views:

58

answers:

2

I need a regular expression written to use in gVim that will remove duplicate domains from a list of URLs (gVim can be downloaded here: http://www.vim.org/download.php

I have a list of over 6,000,000 URLs in a .txt file (which opens in gVim for editing).

The URLs are in this format:

http://www.example.com/some-url.php

http://example2.com/another_url.html

http://example3.com/

http://www.example4.com/anotherURL.htm

http://www.example.com/some-url2.htm

http://example.com/some-url3.html

http://www.example2.com/somethingelse.php

http://example5.com

In other words, there is no specific format to the URLs. Some have the WWW, some don't, they all have different formats.

I need a regular expression written for gVim that will remove all duplicate DOMAINs from the list (and it's corresponding URL), leaving behind the first instance it finds.

So it would take the example list posted above, and the end result should look like this:

http://www.example.com/some-url.php

http://example2.com/another_url.html

http://example3.com/

http://www.example4.com/anotherURL.htm

http://example5.com

Here are two nice sites that explain how to use regular expressions within gVim pretty nicely:

http://147.188.192.43/documentation/tutorials/docsystem/build/tutorials/gvim/gvim.html#Vi-Regular-Expressions

http://www.softpanorama.org/Editors/Vimorama/vim_regular_expressions.shtml

A: 

Try this:

%! sort | uniq
Paul Betts
To be completely honest, I'm not even sure HOW to try that, haha. I appreciate the help though!
Robert
+2  A: 

If you want to do it using regular expression, you can try to adjust the following: %s!\v%(^http://%(www\.)?(%([^./]+\.)+[^./]+)%(/.*)?$\_.{-})@<=^http://%(www\.)?\1%(/.*)?\n!!g, but it is will be very slow on 6 billions of urls and does not work for unknown reason. Here is a better approach:

:let g:gotDomains={}
:%g/^/let curDomain=matchstr(getline('.'), '\v^http://%(www\.)?\zs[^/]+') | if !has_key(g:gotDomains, curDomain) | let g:gotDomains[curDomain]=1 | else | delete _ | endif

It is doing the following:

  1. let g:gotDomains={} creates an empty dictionary where we will hold all domains
  2. %g/^/{command} execute {command} on every line
  3. let curDomain=matchstr(...) get domain name

    1. getline('.') from the current line
    2. \v allow me omit writing lots of backslashes in regex (very magic)
    3. ^ from start of string
    4. \zs start match from here (omit capturing everything before \zs)
  4. if !has_key(g:gotDomains, curDomain) if domain has not occurred before.

  5. let g:gotDomains[curDomain]=1 then add it to the list of known domains (we do not need 1 here, I use dictionary only for faster access).
  6. delete _ else delete the line to black hole register (which means, do not save its contents in any registers).
ZyX
WOW! That second solution you provided (and then clearly explained WHY it was a solution) works perfectly! Thank you so much ZyX! I've spent A LOT of time looking for a solution, and that is spot on, exactly. I truly appreciate you taking the time to not only provide the solution, but to then explain it...well, that is truly helpful. Thanks again!
Robert