Как убрать переменные пробелы в каждой строке текстового файла на основе специального условия - однострочный в Python?
У меня есть некоторые данные (текстовые файлы), которые отформатированы самым неровным образом. Я пытаюсь свести к минимуму объем ручной работы по анализу этих данных.
Пример данных:
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
Условия:
- Несколько разделителей должны быть сжаты до разделителя (лучше конвейер? Конечная цель - сохранить эти файлы в базе данных).
- За исключением первого столбца, в других столбцах не будет пробелов, поэтому все эти пробелы могут быть сжаты в канал.
- Только в первом столбце может быть несколько слов с пробелами (Мэри К Джонс). Остальные столбцы в основном цифры и некоторые алфавиты.
- Первый и второй столбцы являются строками. Они почти всегда имеют более одного пробела между ними, поэтому мы можем различать эти 2 столбца. (Если есть один пробел, это риск, на который я готов пойти, учитывая ужасное форматирование!).
- Количество столбцов варьируется, поэтому нам не нужно беспокоиться об именах столбцов. Все, что мы хотим, это извлечь данные каждого столбца.
Надеюсь, у меня есть смысл! У меня есть ощущение, что эту задачу можно выполнить в режиме oneliner. Я не хочу зацикливаться, зацикливаться, зацикливаться:(
Muchos gracias "Pythonistas" за то, что прочитали все до конца и не выходили перед этим предложением!
3 ответа
До сих пор кажется, что в ваших файлах есть какой-то формат:
>>> 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)
Изменение ответа SilentGhost, на этот раз сначала разделяя имя от остальных (разделенных двумя или более пробелами), затем просто разделяя остальные, и, наконец, составляя один список.
import re
for line in open(fname):
name, rest = re.split('\s{2,}', line, maxsplit=1)
print [name] + rest.split()
Этот ответ был написан после того, как ОП признался, что изменил каждую вкладку ("\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 или около того строк (включая строку заголовка). Также было бы полезно, если бы вы могли сказать, какое программное обеспечение производит эти файлы.