这是Python中的解决方案。我已经在我制作的一个小假文件上对其进行了测试。我认为即使是大文件,这也是可以接受的快,因为大部分工作将由 Python 内部的 C 代码完成。我认为这是一个令人愉快且易于理解的程序;我更喜欢 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 社区有一个约定,可以将它用于您实际上并不关心的变量。)如果在输入行解压成五个变量。如果您的输入文件有时可以在一行中有四个单词,或者六个或更多,您可以修改程序以不引发异常;将主循环更改为:
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 次相比,这可能会节省时间。