Есть ли более быстрый способ очистки управляющих символов в файле?

Раньше я очищал данные, используя фрагмент кода ниже

import unicodedata, re, io all_chars = (unichr(i) for i in xrange(0x110000)) control_chars = ''.join(c for c in all_chars if unicodedata.category(c)[0] == 'C') cc_re = re.compile('[%s]' % re.escape(control_chars)) def rm_control_chars(s): # see http://www.unicode.org/reports/tr44/#General_Category_Values return cc_re.sub('', s) cleanfile = [] with io.open('filename.txt', 'r', encoding='utf8') as fin: for line in fin: line =rm_control_chars(line) cleanfile.append(line) 

В файле есть символы новой строки, которые я хочу сохранить.

Следующее записывает время, затраченное на cc_re.sub('', s) чтобы заменить первые несколько строк (1-й столбец – это время, а 2-й столбец – len(s) ):

 0.275146961212 251 0.672796010971 614 0.178567171097 163 0.200030088425 180 0.236430883408 215 0.343492984772 313 0.317672967911 290 0.160616159439 142 0.0732028484344 65 0.533437013626 468 0.260229110718 236 0.231380939484 204 0.197766065598 181 0.283867120743 258 0.229172945023 208 

Как предложил @ashwinichaudhary, используя s.translate(dict.fromkeys(control_chars)) и то же время, что и log log:

 0.464188098907 252 0.366552114487 615 0.407374858856 164 0.322507858276 181 0.35142993927 216 0.319973945618 314 0.324357032776 291 0.371646165848 143 0.354818105698 66 0.351796150208 469 0.388131856918 237 0.374715805054 205 0.363368988037 182 0.425950050354 259 0.382766962051 209 

Но для моего 1GB текста код очень медленный. Есть ли другой способ очистки контролируемых символов?

6 Solutions collect form web for “Есть ли более быстрый способ очистки управляющих символов в файле?”

нашел решение рабочего символа charater, я скамейке отметил его с использованием файла 100K:

 import unicodedata, re, io from time import time # This is to generate randomly a file to test the script from string import lowercase from random import random all_chars = (unichr(i) for i in xrange(0x110000)) control_chars = [c for c in all_chars if unicodedata.category(c)[0] == 'C'] chars = (list(u'%s' % lowercase) * 115117) + control_chars fnam = 'filename.txt' out=io.open(fnam, 'w') for line in range(1000000): out.write(u''.join(chars[int(random()*len(chars))] for _ in range(600)) + u'\n') out.close() # version proposed by alvas all_chars = (unichr(i) for i in xrange(0x110000)) control_chars = ''.join(c for c in all_chars if unicodedata.category(c)[0] == 'C') cc_re = re.compile('[%s]' % re.escape(control_chars)) def rm_control_chars(s): return cc_re.sub('', s) t0 = time() cleanfile = [] with io.open(fnam, 'r', encoding='utf8') as fin: for line in fin: line =rm_control_chars(line) cleanfile.append(line) out=io.open(fnam + '_out1.txt', 'w') out.write(''.join(cleanfile)) out.close() print time() - t0 # using a set and checking character by character all_chars = (unichr(i) for i in xrange(0x110000)) control_chars = set(c for c in all_chars if unicodedata.category(c)[0] == 'C') def rm_control_chars_1(s): return ''.join(c for c in s if not c in control_chars) t0 = time() cleanfile = [] with io.open(fnam, 'r', encoding='utf8') as fin: for line in fin: line = rm_control_chars_1(line) cleanfile.append(line) out=io.open(fnam + '_out2.txt', 'w') out.write(''.join(cleanfile)) out.close() print time() - t0 

выход:

 114.625444174 0.0149750709534 

Я пробовал файл 1Gb (только для второго), и он длился 186 секунд.

Я также написал эту другую версию того же скрипта, немного быстрее (176s) и более эффективную память (для очень больших файлов, не соответствующих RAM):

 t0 = time() out=io.open(fnam + '_out5.txt', 'w') with io.open(fnam, 'r', encoding='utf8') as fin: for line in fin: out.write(rm_control_chars_1(line)) out.close() print time() - t0 

Как и в UTF-8, все управляющие символы закодированы в 1 байт (совместимы с ASCII) и ниже 32, я предлагаю этот быстрый фрагмент кода:

 #!/usr/bin/python import sys ctrl_chars = [x for x in range(0, 32) if x not in (ord("\r"), ord("\n"), ord("\t"))] filename = sys.argv[1] with open(filename, 'rb') as f1: with open(filename + '.txt', 'wb') as f2: b = f1.read(1) while b != '': if ord(b) not in ctrl_chars: f2.write(b) b = f1.read(1) 

Достаточно ли этого?

Это должно быть в python? Как насчет очистки файла перед его чтением в python для начала. Используйте sed, который будет обрабатывать его по очереди в любом случае.

См. Удаление управляющих символов с помощью sed .

и если вы подключите его к другому файлу, вы можете открыть его. Я не знаю, как быстро это будет. Вы можете сделать это в скрипте оболочки и протестировать его. согласно этой странице – sed – 82M символов в секунду.

Надеюсь, поможет.

Если вы хотите, чтобы он двигался очень быстро? Разбейте свой вход на несколько фрагментов, завершите этот код перебора данных как метод и используйте пакет multiprocessing Python для его параллелизации, записывая в обычный текстовый файл. Идти по-характеру – самый простой способ хрустить такие вещи, но это всегда занимает много времени.

https://docs.python.org/3/library/multiprocessing.html

Я удивлен, что никто не упомянул mmap, который мог бы быть здесь подходящим.

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

Вы загружаете файл в память (вид), а затем вы можете фактически запустить re.sub() над объектом. Это помогает устранить узкое место ввода-вывода и позволяет вам изменить байты на месте, прежде чем записывать их обратно.

После этого вы можете поэкспериментировать с str.translate () vs re.sub (), а также включать любые дополнительные оптимизации, такие как двойной буферный CPU и IO или использование нескольких ядер или потоков CPU.

Но это будет выглядеть примерно так;

 import mmap f = open('test.out', 'r') m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) 

Хорошая выдержка из документации mmap;

Вы можете использовать объекты mmap в большинстве мест, где ожидаются строки; например, вы можете использовать модуль re для поиска по файлу с отображением памяти. Поскольку они изменяемы, вы можете изменить один символ, выполнив obj [index] = 'a', ..

Несколько вещей я попробую.

Во-первых, замените замену всем регулярным выражением.

Во-вторых, установите класс char regex с известными диапазонами символов управления вместо
класса индивидуального контроля.
(Это означает, что двигатель не оптимизирует его для диапазонов.
Диапазон требует двух условий на уровне сборки,
в отличие от отдельных условных для каждого символа в классе)

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

Я не знаю синтаксиса питонов для конструкций регулярных выражений с верхней части головы,
ни все управляющие коды в Юникоде, но результат будет выглядеть как-то
как это:

 [\u0000-\u0009\u000B\u000C\u000E-\u001F\u007F]+ 

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

При прочих равных условиях регулярное выражение (как описано выше) является самым быстрым способом.

  • UnicodeEncodeError: кодек ascii не может кодировать символ u '\ xe7' в позиции 17710: порядковый номер не в диапазоне (128)
  • Общая поддержка Unicode / UTF-8 для файлов csv в Python 2.6
  • Удаление символов, отличных от ASCII, из строки с использованием python / django
  • Декодировать строку ENCODED unicode в Python
  • ошибка unicode при сохранении объекта в django admin
  • Функция python isdigit () возвращает true для символа без цифры u '\ u2466'
  • Кодек UCS-2 не может кодировать символы в позиции 1050-1050
  • Python: как преобразовать строку кода utf-8 в строку?
  • Python - лучший язык программирования в мире.