Python:仅替换字符串中的一个实例
我有一些样本数据,长得像这样:
ATOM 973 CG ARG A 61 -21.593 8.884 69.770 1.00 25.13 C
ATOM 974 CD ARG A 61 -21.610 7.433 69.314 1.00 23.44 C
ATOM 975 NE ARG A 61 -21.047 7.452 67.937 1.00 12.13 N
我想要替换第六列,只有第六列,替换的方式是把一个偏移值加上去,在这个例子中,偏移值是308。
所以61加上308等于369,因此第六列中的61应该被替换成369。
我不能用 str.split()
来分割这一行,因为行之间的空格非常重要。
我试过用 str.replace()
,但是第二列的值可能会和第六列的值重叠。
我也尝试过把行反转,然后用 str.replace()
,但第七、八、九、十和十一列的值也可能和要替换的字符串重叠。
到目前为止,我写的代码很糟糕(除了在第七、八、九、十和/或十一列的值重叠的情况下,部分有效):
with open('2kqx.pdb', 'r') as inf, open('2kqx_renumbered.pdb', 'w') as outf:
for line in inf:
if line.startswith('ATOM'):
segs = line.split()
if segs[4] == 'A':
offset = 308
number = segs[5][::-1]
replacement = str((int(segs[5])+offset))[::-1]
print number[::-1],replacement
line_rev = line[::-1]
replaced_line = line_rev.replace(number,replacement,1)
print line
print replaced_line[::-1]
outf.write(replaced_line[::-1])
上面的代码产生了下面的输出。你可以看到在第二行,第六列没有被改变,但在第七列却被改变了。我原本以为通过反转字符串可以避免与第二列的重叠,但我忘记了其他列的情况,我真的不知道该怎么解决这个问题。
ATOM 973 CG ARG A 369 -21.593 8.884 69.770 1.00 25.13 C
ATOM 974 CD ARG A 61 -21.3690 7.433 69.314 1.00 23.44 C
ATOM 975 NE ARG A 369 -21.047 7.452 67.937 1.00 12.13 N
2 个回答
你最好不要自己尝试解析 PDB
文件。
使用一个 PDB 解析器。市面上有很多免费的解析器,通常包含在生物或计算化学的软件包中,比如说
如果你的输入文件是 raw.pdb
,那么用 biopython 来处理的方法如下:
from Bio.PDB import PDBParser, PDBIO
parser=PDBParser()
structure = parser.get_structure('some_id', 'raw.pdb')
for r in structure.get_residues():
r.id = (r.id[0], r.id[1] + 308, r.id[2])
io = PDBIO()
io.set_structure(structure)
io.save('shifted.pdb')
我查了一下,发现了一个快速解决你特定问题的方法(不需要第三方依赖):
http://code.google.com/p/pdb-tools/
在这里有很多其他有用的 pdb-python 脚本工具,其中有一个脚本 pdb_offset.py
这个脚本是独立的,我只是复制了它的 pdb_offset
方法来演示它的工作原理,你的三行示例代码在 raw.pdb
中:
def pdbOffset(pdb_file, offset):
"""
Adds an offset to the residue column of a pdb file without touching anything
else.
"""
# Read in the pdb file
f = open(pdb_file,'r')
pdb = f.readlines()
f.close()
out = []
for line in pdb:
# For and ATOM record, update residue number
if line[0:6] == "ATOM " or line[0:6] == "TER ":
num = offset + int(line[22:26])
out.append("%s%4i%s" % (line[0:22],num,line[26:]))
else:
out.append(line)
return "".join(out)
print pdbOffset('raw.pdb', 308)
它会输出
ATOM 973 CG ARG A 369 -21.593 8.884 69.770 1.00 25.13 C
ATOM 974 CD ARG A 369 -21.610 7.433 69.314 1.00 23.44 C
ATOM 975 NE ARG A 369 -21.047 7.452 67.937 1.00 12.13 N
data = """\
ATOM 973 CG ARG A 61 -21.593 8.884 69.770 1.00 25.13 C
ATOM 974 CD ARG A 61 -21.610 7.433 69.314 1.00 23.44 C
ATOM 975 NE ARG A 61 -21.047 7.452 67.937 1.00 12.13 N"""
offset = 308
for line in data.split('\n'):
line = line[:22] + " {:<5d} ".format(int(line[22:31]) + offset) + line[31:]
print line
我没有精确计算空格的数量,这只是一个大概的估计。如果你想要比代码中随意出现的数字22和31更灵活的方式,你需要找到一个方法来确定你的开始和结束位置(不过这和我假设数据是固定列格式的想法是相反的)。