gpt4 book ai didi

python - 如何使用awk替换所有组合中的不同文本 block ?

转载 作者:行者123 更新时间:2023-11-28 20:44:29 28 4
gpt4 key购买 nike

我正试着用这样的模式来替换一块块线条:
一组线由下面的线组成,这些线有一个小数目。
当一行有“=”时,这个行块可以替换以“=”命名的块
让我们看一个例子,这个输入:

01 hello
02 stack
02 overflow
04 hi
02 friends = overflow
03 this
03 is
03 my = is
03 life
02 lol
02 im
02 joking = im
03 filler

将生成以下输出(每个hello块是数组的一个元素):
01 hello
02 stack
02 overflow
04 hi
02 lol
02 im

01 hello
02 stack
02 overflow
04 hi
02 lol
02 joking = im
03 filler

01 hello
02 stack
02 friends = overflow
03 this
03 is
03 life
02 lol
02 im

01 hello
02 stack
02 friends = overflow
03 this
03 is
03 life
02 lol
02 joking = im
03 filler

01 hello
02 stack
02 friends = overflow
03 this
03 my = is
03 life
02 lol
02 im

01 hello
02 stack
02 friends = overflow
03 this
03 my = is
03 life
02 lol
02 joking = im
03 filler

我就这样试过了:
#!/bin/bash

awk '{

if ($0~/=/){
level=$1
oc=1
}else if (oc && $1<=level){
oc=0
}

if (!oc){
print
}

}' input.txt

但它只返回我需要的第一个输出,我不知道如何跳过 03 life中的 friends字。
如何生成这些输出?
如果对您更方便的话,我不介意使用python或perl解决方案。

最佳答案

下面是一个python脚本,用于读取cobol输入文件并打印出已定义和重定义变量的所有可能组合:

#!/usr/bin/python
"""Read cobol file and print all possible redefines."""
import sys
from itertools import product

def readfile(fname):
"""Read cobol file & return a master list of lines and namecount of redefined lines."""
master = []
namecount = {}
with open(fname) as f:
for line in f:
line = line.rstrip(' .\t\n')
if not line:
continue
words = line.split()
n = int(words[0])
if '=' in words or 'REDEFINES' in words:
name = words[3]
else:
name = words[1]
master.append((n, name, line))
namecount[name] = namecount.get(name, 0) + 1
# py2.7: namecount = {key: val for key, val in namecount.items() if val > 1}
namecount = dict((key, val) for key, val in namecount.items() if val > 1)

return master, namecount

def compute(master, skip=None):
"""Return new cobol file given master and skip parameters."""
if skip is None:
skip = {}
seen = {}
skip_to = None
output = ''
for n, name, line in master:
if skip_to and n > skip_to:
continue
seen[name] = seen.get(name, 0) + 1
if seen[name] != skip.get(name, 1):
skip_to = n
continue
skip_to = None
output += line + '\n'
return output

def find_all(master, namecount):
"""Return list of all possible output files given master and namecount."""
keys = namecount.keys()
values = [namecount[k] for k in keys]
out = []
for combo in product(*[range(1, v + 1) for v in values]):
skip = dict(zip(keys, combo))
new = compute(master, skip=skip)
if new not in out:
out.append(new)
return out

def main(argv):
"""Process command line arguments and print results."""
fname = argv[-1]
master, namecount = readfile(fname)
out = find_all(master, namecount)
print('\n'.join(out))

if __name__ == '__main__':
main(sys.argv)

如果上述脚本保存在名为 cobol.py的文件中,则If可以运行为:
python cobol.py name_of_input_file

定义和重定义的各种可能组合将显示在stdout上。
此脚本在python2(2.6+)或python3下运行。
解释
代码使用三个函数:
readfile读取输入文件并返回两个变量,这些变量总结了其中的结构。
compute接受两个参数,并从中计算输出块。
find_all确定所有可能的输出块,使用 compute创建它们,然后将它们作为列表返回。
让我们更详细地看一下每个函数:
readfile
readfile将输入文件名作为参数,并返回列表 master和字典 namecount。对于输入文件中的每一个非空行,列表 master都有一个元组,包含(1)级别号,(2)定义或重新定义的名称,以及(2)原始行本身。对于示例输入文件, readfile返回以下值:
[(1, 'hello', '01 hello'),
(2, 'stack', ' 02 stack'),
(2, 'overflow', ' 02 overflow'),
(4, 'hi', ' 04 hi'),
(2, 'overflow', ' 02 friends = overflow'),
(3, 'this', ' 03 this'),
(3, 'is', ' 03 is'),
(3, 'is', ' 03 my = is'),
(3, 'life', ' 03 life'),
(2, 'lol', ' 02 lol'),
(2, 'im', ' 02 im'),
(2, 'im', ' 02 joking = im'),
(3, 'filler', ' 03 filler')]

master还返回dictionary readfile,dictionary namecount对每个重新定义的名称都有一个条目,并统计该名称有多少个定义/重新定义。对于示例输入文件, namecount具有以下值:
{'im': 2, 'is': 2, 'overflow': 2}

这表示 imisoverflow都有两个可能的值。
readfile当然是设计用来处理问题当前版本中的输入文件格式的。在可能的情况下,它也被设计成使用这个问题以前版本的格式。例如,接受变量重新定义,无论它们是用等号(当前版本)表示,还是像以前的版本那样用单词 REFDEFINES表示。这是为了使这个脚本尽可能灵活。
compute
函数 compute生成每个输出块。它使用两个参数。第一个是 master,它直接来自 readfile。第二个是 skip,它来自 namecount返回的 readfile字典。例如, namecount字典指出 im有两种可能的定义。这显示了如何使用 compute为每一个生成输出块:
In [14]: print compute(master, skip={'im':1, 'is':1, 'overflow':1})
01 hello
02 stack
02 overflow
04 hi
02 lol
02 im

In [15]: print compute(master, skip={'im':2, 'is':1, 'overflow':1})
01 hello
02 stack
02 overflow
04 hi
02 lol
02 joking = im
03 filler

注意,上面对 compute的第一个调用生成了使用 im的第一个定义的块,第二个调用生成了使用第二个定义的块。
find_all
有了以上两个功能,显然最后一步就是生成所有不同的定义组合并打印出来。这就是函数 find_all的作用。使用 masternamecount作为 readfile的返回,它系统地运行定义和调用 compute的所有可用组合,为每个定义和调用创建一个块。它收集所有可以用这种方式创建的唯一块并返回它们。
find_all返回的输出是字符串列表。每个字符串都是与定义/重定义的一个组合相对应的块。使用问题的示例输入,这将显示 find_all返回的内容:
In [16]: find_all(master, namecount)
Out[16]:
['01 hello\n 02 stack\n 02 overflow\n 04 hi\n 02 lol\n 02 im\n',
'01 hello\n 02 stack\n 02 friends = overflow\n 03 this\n 03 is\n 03 life\n 02 lol\n 02 im\n',
'01 hello\n 02 stack\n 02 overflow\n 04 hi\n 02 lol\n 02 joking = im\n 03 filler\n',
'01 hello\n 02 stack\n 02 friends = overflow\n 03 this\n 03 is\n 03 life\n 02 lol\n 02 joking = im\n 03 filler\n',
'01 hello\n 02 stack\n 02 friends = overflow\n 03 this\n 03 my = is\n 03 life\n 02 lol\n 02 im\n',
'01 hello\n 02 stack\n 02 friends = overflow\n 03 this\n 03 my = is\n 03 life\n 02 lol\n 02 joking = im\n 03 filler\n']

例如,让我们以 find_all返回的第四个字符串为例,为了获得更好的格式,我们将 print它:
In [18]: print find_all(master, namecount)[3]
01 hello
02 stack
02 friends = overflow
03 this
03 is
03 life
02 lol
02 joking = im
03 filler

在完整的脚本中, find_all的输出组合在一起并按如下方式打印到标准输出:
out = find_all(master, namecount)              
print('\n'.join(out))

这样,输出将显示所有可能的块。
问题早期版本的答案
原题答案
awk 'f==0 && !/REDEFINES/{s=s"\n"$0;next} /REDEFINES/{f=1;print s t>("output" ++c ".txt");t=""} {t=t"\n"$0} END{print s t>("output" ++c ".txt")}' input

说明:
此程序具有以下变量:
f是一个标志,在第一次重定义之前为零,之后为一。
s包含第一次重定义之前的所有文本。
t包含当前重定义的文本。
c是用于确定输出名称的计数器。
代码的工作原理如下:
f==0 && !/REDEFINES/{s=s"\n"$0;next}
在遇到第一个重定义之前,文本保存在变量 s中,我们跳过其余命令并跳到 next行。
/REDEFINES/{f=1;print s t>("output" ++c ".txt");t=""}
每次遇到重定义行时,我们都将标志 f设置为1,并将prolog节 s和当前重定义节一起打印到名为 outputn.txt的文件中,其中n被计数器 c的值替换。
因为我们在一个新的重定义部分的开始,变量 t被设置为空。
{t=t"\n"$0}
将此重定义的当前行保存到变量 t
END{print s t>("output" ++c ".txt")}
将打印最后一个重定义节的输出文件。
小的改进
上面代码生成的每个输出文件都有一个前导空行。下面的代码通过 awk substr函数删除:
awk '/REDEFINES/{f=1;print substr(s,2) t>("output" ++c ".txt");t=""} f==0 {s=s"\n"$0;next} {t=t"\n"$0} END{print substr(s,2) t>("output" ++c ".txt")}' input

对于变体,这个版本的逻辑稍有不同,但在其他方面,会得到相同的结果。
修改问题的答案
awk 'f==1 && pre==$1 && !/REDEFINES/{tail=tail "\n" $0} /REDEFINES/{pre=$1;f=1;t[++c]="\n"$0} f==0 {head=head"\n"$0;next} pre!=$1{t[c]=t[c]"\n"$0} END{for (i=0;i<=c;i++) {print head t[i] tail>("output" (i+1) ".txt")}}' file

关于python - 如何使用awk替换所有组合中的不同文本 block ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26196691/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com