Проблемы с сортировкой при использовании списка - PullRequest
3 голосов
/ 31 марта 2012

У меня есть файл .txt, который содержит список IP-адресов:

111.67.74.234:8080
111.67.75.89:8080
12.155.183.18:3128
128.208.04.198:2124
142.169.1.233:80 

Хотя это намного больше:)

Во всяком случае, импортировал это в список, используя Python, и я пытаюсь его отсортировать, но у меня проблемы. У кого-нибудь есть идеи?

EDIT: Хорошо, так как это было расплывчато, это то, что я так справедливо.

f = open("/Users/jch5324/Python/Proxy/resources/data/list-proxy.txt", 'r+')
lines = [x.split() for x in f]
new_file = (sorted(lines, key=lambda x:x[:18]))

Ответы [ 3 ]

5 голосов
/ 31 марта 2012

Вы, вероятно, сортируете их путем сравнения строк ascii ('.' <'5' и т. Д.), Когда вы предпочитаете, чтобы они сортировались численно.Попробуйте преобразовать их в кортежи целых чисел, а затем отсортировать: </p>

def ipPortToTuple(string):
    """
        '12.34.5.678:910' -> (12,34,5,678,910)
    """
    ip,port = string.strip().split(':')
    return tuple(int(i) for i in ip.split('.')) + (port,)

with open('myfile.txt') as f:
    nonemptyLines = (line for line in f if line.strip()!='')
    sorted(nonemptyLines, key=ipPortToTuple)

edit: Ошибка ValueE, которую вы получаете, заключается в том, что ваши текстовые файлы не полностью находятся в #. #.#. #: # формат, как вы подразумеваете.(Могут быть комментарии или пустые строки, хотя в этом случае ошибка намекает на наличие строки с более чем одним символом ':'.) Вы можете использовать методы отладки, чтобы разобраться в своей проблеме, поймав исключение и выбрав полезныйданные отладки:

def tryParseLines(lines):
    for line in lines:
        try:
            yield ipPortToTuple(line.strip())
        except Exception:
            if __debug__:
                print('line {} did not match #.#.#.#:# format'.format(repr(line)))

with open('myfile.txt') as f:
    sorted(tryParseLines(f))

Я был немного неаккуратен в том, что он по-прежнему пропускает некоторые недействительные IP-адреса (например, #. #. #. #. # или 257.-1. #. #).Ниже приведено более подробное решение, которое позволяет вам выполнять такие вещи, как сравнение IP-адресов с операторами <, а также выполнять естественную сортировку:

#!/usr/bin/python3

import functools
import re

@functools.total_ordering
class Ipv4Port(object):
    regex = re.compile(r'(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}):(\d{1,5})')

    def __init__(self, ipv4:(int,int,int,int), port:int):
        try:
            assert type(ipv4)==tuple and len(ipv4)==4, 'ipv4 not 4-length tuple'
            assert all(0<=x<256 for x in ipv4), 'ipv4 numbers not in valid range (0<=n<256)'
            assert type(port)==int, 'port must be integer'
        except AssertionError as ex:
            print('Invalid IPv4 input: ipv4={}, port={}'.format(repr(ipv4),repr(port)))
            raise ex

        self.ipv4 = ipv4
        self.port = port

        self._tuple = ipv4+(port,)

    @classmethod
    def fromString(cls, string:'12.34.5.678:910'):
        try:
            a,b,c,d,port = cls.regex.match(string.strip()).groups()
            ip = tuple(int(x) for x in (a,b,c,d))
            return cls(ip, int(port))
        except Exception as ex:
            args = list(ex.args) if ex.args else ['']
            args[0] += "\n...indicating ipv4 string {} doesn't match #.#.#.#:# format\n\n".format(repr(string))
            ex.args = tuple(args)
            raise ex

    def __lt__(self, other):
        return self._tuple < other._tuple
    def __eq__(self, other):
        return self._tuple == other._tuple

    def __repr__(self):
        #return 'Ipv4Port(ipv4={ipv4}, port={port})'.format(**self.__dict__)
        return "Ipv4Port.fromString('{}.{}.{}.{}:{}')".format(*self._tuple)

, а затем:

def tryParseLines(lines):
    for line in lines:
        line = line.strip()
        if line != '':
            try:
                yield Ipv4Port.fromString(line)
            except AssertionError as ex:
                raise ex
            except Exception as ex:
                if __debug__:
                    print(ex)
                raise ex

Демонстрация:

>>> lines = '222.111.22.44:214 \n222.1.1.1:234\n 23.1.35.6:199'.splitlines()
>>> sorted(tryParseLines(lines))
[Ipv4Port.fromString('23.1.35.6:199'), Ipv4Port.fromString('222.1.1.1:234'), Ipv4Port.fromString('222.111.22.44:214')]

Изменение значений, например, на 264... или ...-35... приведет к соответствующим ошибкам.

0 голосов
/ 31 марта 2012

@ Решение Ninjagecko - лучшее, но есть еще один способ сделать это, используя re:

>>> import re
>>> with open('ips.txt') as f:
        print sorted(f, key=lambda line: map(int, re.split(r'\.|:', line.strip())))


['12.155.183.18:3128\n', '111.67.74.234:8080\n', '111.67.75.89:8080\n',
'128.208.04.198:2124\n', '142.169.1.233:80 \n']
0 голосов
/ 31 марта 2012

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

строки будут одинаковой длины и могут быть отсортированы. После этого мы просто удаляем все пробелы.

Вы можете погуглить и найти другие примеры этого.

for i in range(len(address)):
    address[i] = "%3s.%3s.%3s.%3s" % tuple(ips[i].split("."))
address.sort()
for i in range(len(address)):
    address[i] = address[i].replace(" ", "")

если у вас есть тонна IP-адреса, вы получите лучшее время обработки, если будете использовать c ++. это будет больше работы заранее, но вы получите лучшее время обработки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...