使用python修复列缩进

时间:2014-09-26 08:22:43

标签: python awk

有一种名为.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,但我遇到了缩进问题。

4 个答案:

答案 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

格式化之前将各个字段解析为相应的数据类型(可能使用duck-typing)
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个字符左对齐。