Указание символов в питоне - PullRequest
0 голосов
/ 18 декабря 2009

Мне нужна функция, которая перебирает все строки в файле.
Вот что у меня есть:

def LineFeed(file):
    ret = ""
    for byte in file:
        ret = ret + str(byte)
        if str(byte) == '\r':
            yield ret
            ret = ""

Все строки в файле заканчиваются на \ r (не \ n), и я читаю его в режиме "rb "(я должен прочитать этот файл в двоичном виде). yield не работает и ничего не возвращает. Может быть, есть проблема со сравнением? Я просто не уверен, как вы представляете байт / символ в питоне.

У меня возникает мысль, что если вы выполняете цикл for для файла "rb", он все еще пытается перебирать строки, а не байты ... Как я могу перебирать байты? Моя проблема в том, что у меня нет стандартных окончаний строк. Также мой файл заполнен 0x00 байтами, и я хотел бы избавиться от них всех, поэтому я думаю, что мне понадобится вторая функция yield, как я могу это реализовать, я просто не знаю, как представить байты 0x00 в python или NULL char.

Ответы [ 5 ]

2 голосов
/ 18 декабря 2009

Возможно, если бы вы объяснили, что представляет собой этот файл, почему он содержит много символов \ x00, почему вы считаете, что вам нужно прочитать его в двоичном режиме, мы могли бы помочь вам в решении вашей основной проблемы.

В противном случае попробуйте следующий код; это позволяет избежать какой-либо зависимости (или вмешательства) от соглашения о конце строки вашей операционной системы.

lines = open("the_file", "rb").read().split("\r")
for line in lines:
    process(line)

Редактировать: байт NSC (не NULL) ASCII равен "\ x00".

2 голосов
/ 18 декабря 2009

Я думаю, что вас смущает то, что делает "для x в файле". Предполагая, что вы получили свой дескриптор типа «file = open (file_name)», байт в этом случае будет всей строкой, а не одним символом. Таким образом, вы вызываете yield только тогда, когда вся строка состоит из одного возврата каретки. Попробуйте изменить «byte» на «line» и повторить его со вторым циклом.

1 голос
/ 18 декабря 2009

Если вы контролируете, как открыть файл, я бы порекомендовал открыть его с помощью универсальных символов новой строки, так как \ r не распознается как символ перевода строки, если вы просто используете режим 'rb', но это если Вы используете 'Urb'.

Это будет работать только в том случае, если вы не включаете в свой двоичный файл \ n, а также \ r, поскольку различие между \ r и \ n теряется при использовании универсальных символов новой строки.

Предполагая, что вы хотите, чтобы ваши полученные строки все еще заканчивались \ r:

NUL = '\x00'
def lines_without_nulls(path):
    with open(path, 'Urb') as f:
        for line in f:
            yield line.replace(NUL, '').replace('\n', '\r')
0 голосов
/ 18 декабря 2009

Итак, ваша проблема - перебирать строки файла, открытого в двоичном режиме, в котором в качестве разделителя строк используется '\r'. Поскольку файл находится в двоичном режиме, вы не можете использовать универсальную функцию перевода строки, и получается, что '\r' не интерпретируется как разделитель строк в двоичном режиме.

Чтение символьного файла за символом - ужасно неэффективная вещь в Python, но вот как вы можете перебирать свои строки:

def cr_lines(the_file):
    line = []
    while True:
        byte = the_file.read(1)
        if not byte:
            break
        line.append(byte)
        if byte == '\r':
            yield ''.join(line)
            line = []
    if line:
        yield ''.join(line)

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

Обратите внимание на использование идиомы ''.join(line). Накопление строки с += имеет ужасную производительность и является распространенной ошибкой, допущенной начинающими программистами.

0 голосов
/ 18 декабря 2009

Редактировать:

  • string1 += string2 медленная конкатенация строк. Попробуйте присоединиться к списку строк.

  • ddaa прав - вам не нужен пакет struct, если двоичный файл содержит только ASCII. Кроме того, мой генератор возвращает строку после последнего '\ r', перед EOF. С этими двумя незначительными исправлениями мой код подозрительно похож (практически идентичен) на этот более свежий ответ .

Кодовый фрагмент:

def LineFeed(f):
    ret = []
    while True:
        oneByte = f.read(1)
        if not oneByte: break
        # Return everything up to, but not including the carriage return
        if oneByte == '\r':
            yield ''.join(ret)
            ret = []
        else:
            ret.append(oneByte)
    if oneByte:
        yield ''.join(ret)
if __name__ == '__main__':
    lf = LineFeed( open('filename','rb') )

    for something in lf:
        doSomething(something)
...