Python 在空行中重复数据,直到出现非空行

Python 在空行中重复数据,直到出现非空行,python,awk,formatting,Python,Awk,Formatting,我有一个如下所示的数据文件: xyz123 2.000 -0.3974 0.0 hij123 6.0 lmn123 8.7 efg123 13.9 uvw123

我有一个如下所示的数据文件:

 xyz123            2.000    -0.3974     0.0  hij123       
                                          6.0  lmn123      
                                          8.7  efg123      
                                         13.9  uvw123      
                                         28.5  rst123       
 abc123            10.000     0.1943     0.0  wxy123       
                                         10.7  xyz123       
                                         19.9  pqr123     
                                         20.6  stu123      
                                         20.6  klm123      
 def123            50.000    -0.2595    19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
*uvw123 15.000-0.3635

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
我需要将其转换为:

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
xyz123,2.000,-0.3974,0.0,hij123       
xyz123,2.000,-0.3974,6.0,lmn123      
xyz123,2.000,-0.3974,8.7,efg123      
xyz123,2.000,-0.3974,13.9,uvw123      
xyz123,2.000,-0.3974,28.5,rst123       
abc123,10.000,0.1943,0.0,wxy123       
abc123,10.000,0.1943,10.7,xyz123       
abc123,10.000,0.1943,19.9,pqr123     
abc123,10.000,0.1943,20.6,stu123      
abc123,10.000,0.1943,20.6,klm123      
def123,50.000,-0.2595,19.2,jkl123      
def123,50.000,-0.2595,26.1,stu123      
def123,50.000,-0.2595,27.1,def123     
def123,50.000,-0.2595,27.1,ghi123     
def123,50.000,-0.2595,27.6,abc123
*uvw123,15.000,-0.3635

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
lmn123,40.000,-0.3695,19.2,jkl123      
lmn123,40.000,-0.3695,26.1,stu123      
lmn123,40.000,-0.3695,27.1,def123     
lmn123,40.000,-0.3695,27.1,ghi123     
lmn123,40.000,-0.3695,27.6,abc123
如何使用Python、AWK或sed实现这一点

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123

更新:如果您注意到输入数据中有一行看起来像“uvw123 15.000-0.3635”,那么当我使用aix中的python代码时,这一行就会出错。有没有办法修改代码并正确输出我显示的行?

下面是一个Python解决方案:

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
import re

with open('data.txt') as f:
  prev = []
  for line in f:
    tok = [t for t in re.split(r'\s+', line.rstrip()) if t]
    if len(tok) < len(prev):
      tok = prev[:-len(tok)] + tok
    print ','.join(tok)
    prev = tok
重新导入
将open('data.txt')作为f:
prev=[]
对于f中的行:
tok=[t表示重新拆分(r'\s+',line.rstrip())中的t,如果t]
如果len(tok)

它跟踪每个列(在
prev
中)的最新值,并使用该值填充当前行中缺少的列。

一个简单的grep就可以做到这一点

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
$ cat so.txt 
xyz123 2.000 -0.3974 0.0 hij123
6.0 lmn123
8.7 efg123
13.9 uvw123
28.5 rst123
abc123 10.000 0.1943 0.0 wxy123
10.7 xyz123
19.9 pqr123
20.6 stu123
20.6 klm123
def123 50.000 -0.2595 19.2 jkl123
26.1 stu123
27.1 def123
27.1 ghi123
27.6 abc123
$ cat so.txt | grep "-"
xyz123 2.000 -0.3974 0.0 hij123
def123 50.000 -0.2595 19.2 jkl123
awk
(和
tr
)解决方案,不是特别优雅:

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
awk 'BEGIN { OFS = ","}
  { if (NF == 5) {
    split($0, a); print $1, $2, $3, $4, $5
  } else {
    print a[1], a[2], a[3], $1, $2
  } }' | tr -d ' \t'
分成多行:

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
awk 'BEGIN {
        OFS = ","
    } 
    NF == 5 {
        a = $1; 
        b = $2; 
        c = $3; 
        $1 = $1; 
        print; 
        next
    } 
    {
        $4 = $1; 
        $5 = $2; 
        $1 = a; 
        $2 = b; 
        $3 = c; 
        print
    }' inputfile

执行
$1=$1
将强制使用新的
OFS

重新组合行,前提是文件以制表符分隔

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
您可以迭代每一行,并对每一行应用
split(“\t”)
,例如

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
for line in lines:
    result = line.split("\t")
如果len(result)是5,那么您将进入一个新的部分。您可以这样解压这些值

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
h1, h2, h3, v1, v2 = result
否则就是

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
v1, v2 = result
然后,您可以使用
“,”打印变量。join([h1、h2、h3、v1、v2])

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
至于第二个问题,如果看不到文件中不可见的字符,很难判断。例如,您可以使用vi中的“set list”查看它们。

使用awk:

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
awk 'BEGIN {OFS=","} /^[^ ]/ {f1=$1; f2=$2; f3=$3; f4=$4; f5=$5} /^[ ]/ {f4=$1; f5=$2}  {print f1,f2,f3,f4,f5}' < input.txt
awk'BEGIN{OFS=“,”}/^[^]/{f1=$1;f2=$2;f3=$3;f4=$4;f5=$5}/^[]/{f4=$1;f5=$2}{打印f1、f2、f3、f4、f5}
使用awk:

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
awk 'BEGIN{OFS="\t";} NF==2{print a,b,c,$1,$2}{};NF==5{a=$1; b=$2; c=$3;print $1,$2,$3,$4,$5}{}' logfile 
这首先将输出字段分隔符设置为选项卡(您可以根据需要进行更改),然后查看行中有多少列。如果有5个变量,它将前三个变量设置为变量a、b和c,然后将它们全部打印出来

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
如果只有两列,则打印a、b和c(即最后一整行的前三列),然后打印此行的两列

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
更新:

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
我没有注意到这行只有三列!下面的awk命令应提供您指定的输出:

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
awk 'BEGIN{OFS="\t";} $1~/^[a-z]/{a=$1; b=$2; c=$3;print $1,$2,$3,$4,$5}{}$1!~/^[a-z]/{print a,b,c,$1,$2}{}' logfile

这与之前的工作方式类似,但会查看第一个字段是否以字母开头,而不是查看列数。如果需要,这个正则表达式可以变得更具体。

您可以尝试这样的方法开始使用-

 lmn123            40.000    -0.3695     19.2  jkl123      
                                         26.1  stu123      
                                         27.1  def123     
                                         27.1  ghi123     
                                         27.6  abc123
awk 'NF>3{a=$1;b=$2;c=$3;$1=$1;print;next}NF<3{d=$1;e=$2;print a,b,c,d,e;next}{$1=$1;}1' OFS=',' file

awk'NF>3{a=$1;b=$2;c=$3;$1=$1;print;next}NFWow!!这太完美了。谢谢你的建议和解决方案。这非常有用。嗨,Aix,我已经更新了我的问题,因为我在输入文件中遇到了意外情况。你能再帮我一次密码吗。非常感谢。@Rishi:请另发一个问题,我相信有人会帮助你。@Rishi--如果这篇文章对你有帮助并且(最初)解决了你的问题,你应该接受它作为答案。我相信我确实接受了这个答案,但后来我遇到了意想不到的事情,不得不稍微修改我的问题,这就是为什么我用修改过的版本重新发布了我的问题。如果这造成了混乱,我很抱歉。恕我直言@DennisWilliamson,但你本可以处理得更好:/@Dennis,谢谢你建议我删减提示,这是一个好建议。为供参考,该问题已被编辑。当我发布这个答案时,问题中的输入与so.txt中显示的完全相同,所需的输出是grep的输出。我的空闲时间不超过1分钟,我决定把这段时间花在打开SO,选择这篇文章,努力帮助OP上——带着所有的诚意。所以我不明白,为什么会有这种敌意?请接受我的道歉。然而,在看过问题的原始形式后,我不同意期望的输出与
grep
-所以这不是一个让人们为你写代码的网站。同意……但我并不是试图说服人们为我写代码。大部分时间我自己都能做到。我不是Python专家,我想如果有人能进一步帮助我。谢谢Lattyware。如果你能自己完成大部分工作,那么就去做,然后带着一个特定的问题回来,展示你的代码。这是一个人们可以学习东西的网站。这类问题的答案通常都有值得学习的地方。谢谢John,我运行了您的AWK语句,它做得很好,但它从输出文件中完全删除了这一行“uvw123 15.000-0.3635”。知道为什么吗?对不起,我没注意到那句话!我现在更新了我的答案来解决这个问题。嗨,约翰,你的第一个awk声明效果更好。对于您的新Awk声明,每次重复的第二行是不正确的,它也不会将这一行“uvw123 15.000-0.3635”作为新行。有些事情搞砸了…我正在努力,看看是否可以在不打扰您的情况下修复它。更好,但如果您看到输出,这就是它的功能:def 123,50.000,-0.2595,uvw123,15.000,而不是def 123,50.000,-0.2595,27.6,abc123 uvw123,15.000,-0.3635,