有一种名为.xyz
的文件格式有助于可视化分子键。基本上格式要求特定模式:
在第一行必须有原子数,在我的情况下是30。 之后应该有数据,其中第一行是原子的名称,在我的例子中,它们都是碳。第二行是x信息,第三行是y信息,最后一行是z信息,在我的情况下都是0。缩进应该是正确的,以便所有相应的行应该从同一个地方开始。所以像这样:
30
C x1 y1 z1
C x2 y2 z2
...
...
...
而不是:
30
C x1 y1 z1
C x2 y2 z2
因为这是错误的缩进。
我生成的数据存储在.txt
文件中:
C 2.99996 7.31001e-05 0
C 2.93478 0.623697 0
C 2.74092 1.22011 0
C 2.42702 1.76343 0
C 2.0079 2.22961 0
C 1.50006 2.59812 0
C 0.927076 2.8532 0
C 0.313848 2.98349 0
C -0.313623 2.9837 0
C -0.927229 2.85319 0
C -1.5003 2.5981 0
C -2.00732 2.22951 0
C -2.42686 1.76331 0
C -2.74119 1.22029 0
C -2.93437 0.623802 0
C -2.99992 -5.5509e-05 0
C -2.93416 -0.623574 0
C -2.7409 -1.22022 0
C -2.42726 -1.7634 0
C -2.00723 -2.22941 0
C -1.49985 -2.59809 0
C -0.92683 -2.85314 0
C -0.313899 -2.98358 0
C 0.31363 -2.98356 0
C 0.927096 -2.85308 0
C 1.50005 -2.59792 0
C 2.00734 -2.22953 0
C 2.4273 -1.76339 0
C 2.74031 -1.22035 0
C 2.93441 -0.623647 0
我想通过使所有行从同一点开始来纠正这种缩进。我试图用AWK这样做无济于事。所以我转向Python。到目前为止,我有这个:
#!/usr/bin/env/python
text_file = open("output.txt","r")
lines = text_file.readlines()
myfile = open("output.xyz","w")
for line in lines:
atom, x, y, z = line.split()
x, y, z = map(float(x,y,z))
myfile.write("{}\t {}\t {}\t {}\t".format(atom,x,y,z))
myfile.close()
text_file.close()
但我目前不知道如何将缩进添加到此中。
tl; dr:我有一个数据文件。txt
,我想将其更改为已指定的.xyz
,但我遇到了缩进问题。
答案 0 :(得分:1)
似乎我误解了你的要求......
要使用awk实现固定宽度输出,您可以使用printf
格式字符串,如下所示:
$ awk '{printf "%-4s%12.6f%12.6f%5d\n", $1, $2, $3, $4}' data.txt
C 2.999960 0.000073 0
C 2.934780 0.623697 0
C 2.740920 1.220110 0
C 2.427020 1.763430 0
C 2.007900 2.229610 0
C 1.500060 2.598120 0
C 0.927076 2.853200 0
C 0.313848 2.983490 0
C -0.313623 2.983700 0
# etc.
%
后的数字指定字段的宽度。负数表示输出应保持对齐(如第一列中所示)。我为浮点数指定了6位小数。
要确保输入的每个列之间都有制表符,您可以使用此awk脚本:
awk '{$1=$1}1' OFS="\t" data.txt > output.xyz
$1=$1
只是强制awk触摸每一行,这样可以确保应用新的输出字段分隔符(OFS
)。
awk脚本是从一系列condition { action }
构建的。如果未提供条件,则对每一行执行操作。如果提供了条件但没有提供操作,则默认操作是打印该行。 1
是一个始终求值为true的条件,因此awk会打印该行。
请注意,即使列都是制表符分隔的,它们仍然没有排列,因为每列的内容都是可变长度。
答案 1 :(得分:1)
您的数据格式不正确并转换为字符串。要正确对齐数字和非数字数据,您需要在使用str.format
for line in st.splitlines():
def convert(st):
try:
return int(st)
except ValueError:
pass
try:
return float(st)
except ValueError:
pass
return st
print "{:8}{:12.5f}{:12.5f}{:5d}".format(*map(convert,line.split()))
C 2.99996 0.00007 0
C 2.93478 0.62370 0
C 2.74092 1.22011 0
C 2.42702 1.76343 0
C 2.00790 2.22961 0
C 1.50006 2.59812 0
C 0.92708 2.85320 0
C 0.31385 2.98349 0
C -0.31362 2.98370 0
C -0.92723 2.85319 0
答案 2 :(得分:0)
使用此:awk '{printf "%s\t%10f\t%10f\t%i\n",$1,$2,$3,$4}' atoms
给出这个输出:
C 2.999960 0.000073 0
C 2.934780 0.623697 0
C 2.740920 1.220110 0
C 2.427020 1.763430 0
C 2.007900 2.229610 0
C 1.500060 2.598120 0
C 0.927076 2.853200 0
C 0.313848 2.983490 0
C -0.313623 2.983700 0
C -0.927229 2.853190 0
C -1.500300 2.598100 0
C -2.007320 2.229510 0
C -2.426860 1.763310 0
C -2.741190 1.220290 0
C -2.934370 0.623802 0
C -2.999920 -0.000056 0
C -2.934160 -0.623574 0
C -2.740900 -1.220220 0
C -2.427260 -1.763400 0
C -2.007230 -2.229410 0
C -1.499850 -2.598090 0
C -0.926830 -2.853140 0
C -0.313899 -2.983580 0
C 0.313630 -2.983560 0
C 0.927096 -2.853080 0
C 1.500050 -2.597920 0
C 2.007340 -2.229530 0
C 2.427300 -1.763390 0
C 2.740310 -1.220350 0
C 2.934410 -0.623647 0
这是你的意思还是我误解了?
编辑旁注:我使用标签\t
进行分隔,空格也可以,我将输出限制为精度10,我没有验证输入长度
答案 3 :(得分:0)
您可以使用string formatting打印具有一致填充的值。对于您的情况,您可以将这样的行写入文件:
>>> '%-12s %-12s %-12s %-12s\n' % ('C', '2.99996', '7.31001e-05', '0')
'C 2.99996 7.31001e-05 0 '
"% - 12S"表示"取值的str()并使其至少占用12个字符左对齐。