Как убрать переменные пробелы в каждой строке текстового файла на основе специального условия - однострочный в Python? - PullRequest
3 голосов
/ 06 октября 2010

У меня есть некоторые данные (текстовые файлы), которые отформатированы самым неравномерным образом.Я пытаюсь свести к минимуму объем ручной работы по анализу этих данных.

Пример данных:

Name        Degree      CLASS       CODE        EDU     Scores
--------------------------------------------------------------------------------------
John Marshall       CSC   78659944   89989        BE   900
Think Code DB I10   MSC  87782  1231  MS            878
Mary 200 Jones    CIVIL      98993483  32985        BE       898
John G. S  Mech 7653 54 MS 65
Silent Ghost  Python Ninja 788505  88448  MS Comp  887

Условия:

  • Более одного пробела должно быть сжато доразделитель (лучше конвейер? Конечная цель - сохранить эти файлы в базе данных).
  • За исключением первого столбца, в других столбцах не будет пробелов, поэтому все эти пробелы могут быть сжаты доpipe.
  • Только в первом столбце может быть несколько слов с пробелами (Мэри К Джонс).Остальные столбцы в основном цифры и некоторые алфавиты.
  • Первый и второй столбцы являются строками.Они почти всегда имеют более одного пробела между ними, поэтому мы можем различать эти 2 столбца.(Если есть один пробел, это риск, на который я готов пойти, учитывая ужасное форматирование!).
  • Количество столбцов различается, поэтому нам не нужно беспокоиться об именах столбцов.Все, что мы хотим, - это извлечь данные каждого столбца.

Надеюсь, я понял!У меня есть ощущение, что эту задачу можно выполнить в режиме oneliner.Я не хочу зацикливаться, зацикливаться, зацикливаться: (

Muchos gracias "Pythonistas" для прочтения полностью и не выхода из этого предложения!

Ответы [ 3 ]

3 голосов
/ 06 октября 2010

До сих пор кажется, что в ваших файлах есть какой-то формат:

>>> regex = r'^(.+)\b\s{2,}\b(.+)\s+(\d+)\s+(\d+)\s+(.+)\s+(\d+)'
>>> for line in s.splitlines():
    lst = [i.strip() for j in re.findall(regex, line) for i in j if j]
    print(lst)


[]
[]
['John Marshall', 'CSC', '78659944', '89989', 'BE', '900']
['Think Code DB I10', 'MSC', '87782', '1231', 'MS', '878']
['Mary 200 Jones', 'CIVIL', '98993483', '32985', 'BE', '898']
['John G. S', 'Mech', '7653', '54', 'MS', '65']
['Silent Ghost', 'Python Ninja', '788505', '88448', 'MS Comp', '887']

Regex довольно прост, единственное, на что нужно обратить внимание - это разделители (\s) и разрывы слов(\b) в случае первого разделителя.Обратите внимание, что когда строка не совпадает, вы получаете пустой список как lst.Это был бы флаг чтения, чтобы вызвать взаимодействие с пользователем, описанное ниже.Также вы можете пропустить строки заголовка, выполнив:

>>> file = open(fname)
>>> [next(file) for _ in range(2)]
>>> for line in file:
    ...  # here empty lst indicates issues with regex

Предыдущие варианты:

>>> import re
>>> for line in open(fname):
    lst = re.split(r'\s{2,}', line)
    l = len(lst)
    if l in (2,3):
        lst[l-1:] = lst[l-1].split()
    print(lst)

['Name', 'Degree', 'CLASS', 'CODE', 'EDU', 'Scores']
['--------------------------------------------------------------------------------------']
['John Marshall', 'CSC', '78659944', '89989', 'BE', '900']
['Think Code DB I10', 'MSC', '87782', '1231', 'MS', '878']
['Mary 200 Jones', 'CIVIL', '98993483', '32985', 'BE', '898']
['John G. S', 'Mech', '7653', '54', 'MS', '65']

Другая вещь, которую нужно сделать, это просто позволить пользователю решать, что делать с сомнительными записями:

if l < 3:
    lst = line.split()
    print(lst)
    iname = input('enter indexes that for elements of name: ')     # use raw_input in py2k
    idegr = input('enter indexes that for elements of degree: ')

Хм, у меня все время было впечатление, что второй элемент может содержать пробелы, поскольку это не тот случай, который вы могли бы просто сделать:

>>> for line in open(fname):
    name, _, rest = line.partition('  ')
    lst = [name] + rest.split()
    print(lst)
2 голосов
/ 06 октября 2010

Изменение ответа SilentGhost, на этот раз сначала разделив имя от остальных (разделенных двумя или более пробелами), затем разделив остальные, и, наконец, составив один список.

1 голос
/ 08 октября 2010

Этот ответ был написан после того, как ОП признался, что изменил каждую вкладку ("\ t") в своих данных на 3 пробела (и не упомянул об этом в своем вопросе).

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

Вместо line.replace('\t', ' ' * 3) попробуйте line.expandtabs().

Документы для расширенных таблиц здесь .

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

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

RecordType  ID1                  ID2         Description           
----------- -------------------- ----------- ----------------------
1           12345678             123456      Widget                
4           87654321             654321      Gizmoid

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

sizes = map(len, dash_line.split())

Если не работают expandtabs (), отредактируйте свой вопрос, чтобы показать, что именно у вас есть, т.е. показать результат print repr(line) для первых 5 или около того строк (включая строку заголовка). Также было бы полезно, если бы вы могли сказать, какое программное обеспечение производит эти файлы.

...