Вот решение на Python. Я протестировал его на небольшом поддельном файле, который я создал. Я думаю, что это будет приемлемо быстро даже для большого файла, потому что большая часть работы будет выполняться кодом C внутри Python. И я думаю, что это приятная и простая для понимания программа; Я предпочитаю Python Perl.
import sys
s_usage = """\
Usage: csplit <filename>
Splits input file by columns, writes column 2 to file based on chromosome from column 4."""
if len(sys.argv) != 2 or sys.argv[1] in ("-h", "--help", "/?"):
sys.stderr.write(s_usage + "\n")
sys.exit(1)
# replace these with the actual patterns, of course
lst_pat = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y'
]
d = {}
for s_pat in lst_pat:
# build a dictionary mapping each pattern to an open output file
d[s_pat] = open("my_out_file_" + s_pat, "wt")
if False:
# if the patterns are unsuitable for filenames (contain '*', '?', etc.) use this:
for i, s_pat in enumerate(lst_pat):
# build a dictionary mapping each pattern to an output file
d[s_pat] = open("my_out_file_" + str(i), "wt")
for line in open(sys.argv[1]):
# split a line into words, and unpack into variables.
# use '_' for a variable name to indicate data we don't care about.
# s_data is the data we want, and s_pat is the pattern controlling the output
_, s_data, _, s_pat, _ = line.split()
# use s_pat to get to the file handle of the appropriate output file, and write data.
d[s_pat].write(s_data + "\n")
# close all the output file handles.
for key in d:
d[key].close()
РЕДАКТИРОВАТЬ: Вот еще немного информации об этой программе, так как, похоже, вы будете ее использовать.
Вся обработка ошибок является неявной. Если произойдет ошибка, Python «поднимет исключение», которое прекратит обработку. Например, если один из файлов не открывается, эта программа прекратит выполнение, и Python напечатает трассировку, показывающую, какая строка кода вызвала исключение. Я мог бы обернуть критические части блоком try/except, чтобы отлавливать ошибки, но для такой простой программы я не видел никакого смысла.
Это тонко, но есть проверка, чтобы увидеть, есть ли ровно пять слов в каждой строке входного файла. Когда этот код распаковывает строку, он делает это в пять переменных. (Имя переменной «_» является допустимым именем переменной, но в сообществе Python принято использовать его для переменных, которые на самом деле вам не нужны.) Python вызовет исключение, если в имени не будет ровно пяти слов. входная строка для распаковки в пять переменных. Если в вашем входном файле иногда может быть четыре слова в строке, или шесть или более слов, вы можете изменить программу, чтобы она не вызывала исключение; изменить основной цикл на это:
for line in open(sys.argv[1]):
lst = line.split()
d[lst[3]].write(lst[1] + "\n")
Это разбивает строку на слова, а затем просто присваивает весь список слов одной переменной lst. Так что этой строке кода все равно, сколько слов в строке. Затем следующая строка индексируется в списке, чтобы получить значения. Поскольку Python индексирует список, начиная с 0, второе слово — lst[1]
, а четвертое слово — lst[3]
. Пока в списке есть хотя бы четыре слова, эта строка кода также не вызовет исключения.
И, конечно же, если четвертое слово в строке отсутствует в словаре файловых дескрипторов, Python и в этом случае вызовет исключение. Это остановило бы обработку. Вот пример кода, как использовать блок «try/except» для обработки этого:
for line in open(sys.argv[1]):
lst = line.split()
try:
d[lst[3]].write(lst[1] + "\n")
except KeyError:
sys.stderr.write("Warning: illegal line seen: " + line)
Удачи с вашим проектом.
РЕДАКТИРОВАТЬ: @larelogio указал, что этот код не соответствует коду AWK. В коде AWK есть дополнительный цикл for, который я не понимаю. Вот код Python, делающий то же самое:
for line in open(sys.argv[1]):
lst = line.split()
n = int(lst[1])
for i in range(n, n+53):
d[lst[3]].write(i + "\n")
И вот еще один способ сделать это. Это может быть немного быстрее, но я не проверял это, поэтому я не уверен.
for line in open(sys.argv[1]):
lst = line.split()
n = int(lst[1])
s = "\n".join(str(i) for i in range(n, n+53))
d[lst[3]].write(s + "\n")
Это создает одну строку со всеми числами для записи, а затем записывает их в один фрагмент. Это может сэкономить время по сравнению с вызовом .write()
53 раза.
person
steveha
schedule
21.12.2009