Seite 1 von 2

IP adressen sortieren

Verfasst: Dienstag 22. Juni 2004, 09:18
von xerxes_
hi,
in einer datei sind ip adresse aufgelistet. die IPs sind nicht geordnet, sprich die IPs liegen kreuz und quer herum. nun ist es meine aufgabe diese zu sortieren. ich hab den inhalt der datei in eine liste gepackt und wollte munter mit list.sort() die sache sortieren lassen. hat auch gut funktioniert nur wisst ihr bestimmt schon wie das resultat aussieht.
192.168.0.0
192.168.0.1
192.168.0.10
192.168.0.11
...

nun meine frage an euch wie würdet ihr dieses problem lösen?

Re: IP adressen sortieren

Verfasst: Dienstag 22. Juni 2004, 10:46
von joerg
xerxes_ hat geschrieben: nun meine frage an euch wie würdet ihr dieses problem lösen?

Code: Alles auswählen

ips = ['192.168.0.0', '192.168.0.1', '192.168.0.10', '192.168.0.11']
tmp = [([int(i) for i in ip.split('.')], ip) for ip in ips]
tmp.sort()
ipsorted = [b for a,b in tmp]
Da wird eine Liste gebastelt, deren Elemente Tupel aus den aufbereiteten IPs und den String-IPs sind, dann sortiert, und schließlich wieder die originalen String-IPs rausgesucht.

"Aufbereitung" ist in dem Fall eine Umwandlung des IP-Strings in eine Liste von Zahlen, weil die nämlich besser sortierbar ist.

Alternativ kannst Du zwischenzeitlich auch die Original-Strings vergessen (also aus 'tmp' draußenlassen) und nach dem Sortieren die String-IPs wieder aus den Zahlen zusammenbasteln, das kann übersichtlicher aussehen, aber wird wahrscheinlich nicht schneller sein:

Code: Alles auswählen

tmp = [[int(i) for i in ip.split('.')] for ip in ips]
tmp.sort()
ipsorted = ['%d.%d.%d.%d' % tuple(i) for i in tmp]
Jörg

Verfasst: Dienstag 22. Juni 2004, 12:16
von Gast

Code: Alles auswählen

ips.sort(lambda x,y: cmp(int(x.split(".")[-1]),int(y.split(".")[-1])
@joerg viel zu kompliziert ;)

Verfasst: Dienstag 22. Juni 2004, 12:17
von Gast

Code: Alles auswählen

ips.sort(lambda x,y: cmp(int(x.split(".")[-1]),int(y.split(".")[-1])))
sorry da fehlten klammern

Verfasst: Dienstag 22. Juni 2004, 12:30
von Gast
Bei allen stellen:

Code: Alles auswählen

ips.sort(lambda x,y: cmp([int(i) for i in x.split(".")],[int(i) for i in y.split(".")]))

Verfasst: Dienstag 22. Juni 2004, 12:46
von joerg
Hallo "Gast",
daß man dem sort() eine Vergleichsfunktion schon mitgeben kann, war mir schon bewußt.

Nur ging ich irgendwie davon aus, daß die Liste recht lang ist. Und performancemäßig wird Deine Lösung eher schlecht aussehen. Das wurde IMO auch hier im Forum schon mal diskutiert.

Falls die Geschwindigkeit egal ist, hat so ein Einzeiler natürlich auch einen gewissen Charme. ;-)

Jörg

Verfasst: Dienstag 22. Juni 2004, 13:24
von xerxes_
hi,
eure beispiele funktionieren gut. nun ein weiteres problem:
der inhalt der datei ist folgendermaßen aufgebaut:

192.168.0.21 <aufgelöster hostname> <aufgelöste ipadresse durch hostname>

nun möchte ich gerne die ganze zeile verschieben, jedoch das kriterium bleibt immer die ipadresse. das problem ist, bin nicht so bewandert in der python syntax und im "thinking in python" deshalb suche ich um rat bzw um lösungen.
danke im vorraus
gruß xerxes_

Verfasst: Dienstag 22. Juni 2004, 13:38
von Gast
xerxes_ hat geschrieben: ... das problem ist, bin nicht so bewandert in der python syntax und im "thinking in python" deshalb suche ich um rat bzw um lösungen.
Wenn ein ip.split('.') einen String an den Punkten auftrennt, wie kann man die Zeile dann wohl an Leerzeichen auftrennen, um nur den ersten Teil weiterzuverarbeiten? ;-)

Ersetze mal einen Ausdruck in meinem ersten Vorschlag durch

ip.split(' ')[0].split('.')

Wenn es klappt, war es die richtige Stelle! Wenn nicht, suche weiter! ;-)

Jörg

Verfasst: Dienstag 22. Juni 2004, 13:43
von joerg
Ooops, jetzt isses mir auch passiert, das Einlogenvergessen. Der da oben war von mir!

Jörg

Verfasst: Dienstag 22. Juni 2004, 13:43
von xerxes_
hi,
ich hab vielleicht eine schnelle für mich lösbare lösung erarbeitet :)
und zwar folgendermaßen:

in der datei stehen die ergebnisse einer bestimmten range die aufgelöst wurde zb. 192.168.0.0/19

nun kann ich dem python script die range ja als commandozeilen parameter übergeben -> errechnet die rang -> durchläuft die range -> sucht nach jeder ip in der datei -> findet er was -> nimmt er sich die zeile und schreibt sie einen neue datei... :), schlussendlich kann ich noch einige kosmetische änderung an der datei einfügen zb nach bestimmten bestimmten anzahl von zeilen "seite1" ... "seite2" hinschreiben...
gruß xerxes_

Verfasst: Dienstag 22. Juni 2004, 14:25
von Gast
frage scheint geklärt... aber egal

Code: Alles auswählen

ips.sort(lambda x,y,z={}: cmp(x in z and z[x] or z.__setitem__(x,[int(i) for i in x.split(".")]) or z[x],y in z and z[y] or z.__setitem__(y,[int(i) for i in y.split(".")]) or z[y]))
dies ist schneller ;) aber etz wirds komplizierter ^^
hab grad nen test gemacht deins ist trotzdem schneller um ca 30% als das...

Verfasst: Dienstag 22. Juni 2004, 14:33
von xerxes_

Code: Alles auswählen

import string

source = open("C:\\_dns.log", "r")
dns_list = source.readlines()
source.close()

split_list = []

start1 = 213
start2 = 147
start3 = 0
start4 = 0

ende1 = 213
ende2 = 147
ende3 = 0
ende4 = 255

target = open("C:\\newdns.log", "w")

for j in range(int(start1), int(ende1) + 1):
    for k in range(int(start2), int(ende2) + 1):
        for l in range(int(start3), int(ende3) + 1):
            for h in range(int(start4), int(ende4) + 1):
                
                current_ip = str(j) + "." + str(k) + "." + str(l) + "." + str(h)
                
                for i in dns_list:
                    split_list(string.split(i, " "))
                    
                    try:
                        if(split_list[2] != ''):
                            ip = split_list[2]
                            if(current_ip == ip):
                                target.write(i)
                                break
                                
                        else:
                            ip = split_list[3]
                            if(current_ip == ip):
                                target.write(i)
                                break
                            
                    except:
                        print ''

target.close()

Code: Alles auswählen

>>> 
Traceback (most recent call last):
  File "C:\Python23\Lib\site-packages\Pythonwin\pywin\framework\scriptutils.py", line 310, in RunScript
    exec codeObject in __main__.__dict__
  File "C:\Dokumente und Einstellungen\mz\Desktop\python scripte\sort_advanced.py", line 32, in ?
TypeError: 'list' object is not callable
>>> 
kannste mir helfen jörg?
gruß xerxes_

Verfasst: Dienstag 22. Juni 2004, 14:44
von Dookie
Hi xerxes_,

das is wohl etwas daneben:

Code: Alles auswählen

...
split_list(string.split(i, " "))
...
Und 5 verschachtelte Forschleifen ???


Gruß

Dookie

Verfasst: Dienstag 22. Juni 2004, 15:18
von xerxes_
hi
4 verschachtelte schleifen brauch ich um die range hochzuzählen...

die andere um die liste durchzugehen

Verfasst: Dienstag 22. Juni 2004, 15:20
von xerxes_
hier der nächste fehler

Code: Alles auswählen

>>> 
Traceback (most recent call last):
  File "C:\Python23\Lib\site-packages\Pythonwin\pywin\framework\scriptutils.py", line 310, in RunScript
    exec codeObject in __main__.__dict__
  File "C:\Dokumente und Einstellungen\mz\Desktop\python scripte\sort_advanced.py", line 29, in ?
    current_ip = str(j) + "." + str(k) + "." + str(l) + "." + str(h)
TypeError: 'str' object is not callable
>>> 
wie kann ich denn eine integer variable in string umwandeln?

Verfasst: Dienstag 22. Juni 2004, 16:31
von Dookie
import string braucht man so gut wie nie!
Statt open sollte file verwendet werden.
xrange ist resourcenschonender als range und auch schneller.

Ich hab mir mal erlaubt, Dein Script etwas aufzuräumen.

Code: Alles auswählen

source = file("C:\\_dns.log", "r")

split_list = []

start1 = 213
start2 = 147
start3 = 0
start4 = 0

ende1 = 213
ende2 = 147
ende3 = 0
ende4 = 255

target = file("C:\\newdns.log", "w")

for j in xrange(int(start1), int(ende1) + 1):
    for k in xrange(int(start2), int(ende2) + 1):
        for l in xrange(int(start3), int(ende3) + 1):
            for h in xrange(int(start4), int(ende4) + 1):
               
                current_ip = "%d.%d.%d.%d" % (j, k, l ,h)
               
                for i in source: # geht auch direkt über die Zeilen einer Datei
                    split_list = i.split(" "))
                   
                    try:
                        if split_list[2] != '':
                            ip = split_list[2]
                            if current_ip == ip:
                                target.write(i)
                                break
                               
                        else:
                            ip = split_list[3]
                            if current_ip == ip:
                                target.write(i)
                                break
                           
                    except: # was willst hier abfangen?
                        print 'oops' # daß zumindest was ausgegeben wird

target.close()
source.close()
Gruß

Dookie

Verfasst: Dienstag 22. Juni 2004, 19:53
von xerxes_
hi dookie,
hab mir den code angeschaut, danke für die überarbeitung. ich hab versucht den code zu interpretieren unter linux mit folgenden versionen
python2 und python2.3 jedoch kommt folgende warnung

Code: Alles auswählen

sys:1: DeprecationWarning: Non-ASCII character '\xfc' in file sort.py on line 24, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
der code lässt sich auszuführen, nur beträgt das ergebnis eine zeile :).
was bedeutet das und was kann ich dagegen tun?
ich hab mir die page angeschaut jedoch weis ich nichts damit anzufangen
gruß xerxes_

Verfasst: Dienstag 22. Juni 2004, 20:12
von xerxes_
sorry hab mich vertan, das ergebnis ist korrekt würde mich aber dennoch interessieren was diese warnung soll.
ich las irgendwas mit einem zeichensatz. man sollte einen globalen zeichensatz benutzen damit auch andere programmiern besonders aus anderen ländern gleichberechtigt sind beim lesen des codes...
gruß xerxes

Verfasst: Dienstag 22. Juni 2004, 20:13
von Dookie
änder mal das ü in ue

Code: Alles auswählen

for i in source: # geht auch direkt ueber die Zeilen einer Datei
ich hab leider keine _dns.log kann das Script leider nicht testen, was heist das Ergebnis beträgt eine Zeile? fehlen Zeilenumbrüche oder wird nur eine Zeile aus source nach target geschrieben?


Gruß

Dookie

Verfasst: Dienstag 22. Juni 2004, 20:28
von xerxes_
so wie gesagt es funktioniert alles so wie es auch soll :) danke für deine hilfe. aber eins wollte ich an diesem programm noch modifizieren. ich möchte gerne commandozeilenparameter verarbeiten. ich denke mal in python gibt es sowas in der art wie argc und argv
gruß xerxes