繁体   English   中英

如何在awk / sed / python中用另一行替换一行的一个字段?

[英]How to replace one field of a line by another line in awk/sed/python?

input.txt中

A(0,1,2)
...
B(A,3)
...
C(B,4,5)

如果函数的第一个参数不等于0但对应于函数名,我想用所有相应函数的参数替换它(例如,将上面函数B中的第一个参数'A'替换​​为函数A的所有参数)。 这是期待的

output.txt的

A(0,1,2)
...
B(0,1,2,3)
...
C(0,1,2,3,4,5)

我们怎么能用awk / sed或python做到这一点?

编辑:

我的一个想法是将函数名称作为变量存储,将其参数作为值存储在bash中。 在python中,我们可以使用dict,并将函数名称视为键,将其参数视为值。 实施并不那么容易。

AWK

awk -F'[()]' '
    $2 !~ /^0,/ {
        split($2, a, /,/)
        sub(/^[^,]+/, val[a[1]], $2)
    } 
    {
        val[$1] = $2
        print $1 "(" $2 ")"
    }
' input.txt > output.txt

其中sub(/^[^,]+/, val[a[1]], $2)用于匹配$2中的第一个参数,并将其替换为val[a[1]]的值,该值由在前一行执行val[$1] = $2

这是Python的解决方案:

import re

with open('input.txt') as f:
    data = f.read()
data = [line.strip() for line in data.split('\n') if line]
sets, output = {}, open('output.txt', 'w')
for line in data:
    if line == '...':
        output.write(line + '\n')
        continue
    sets[line[0]] = line[2:-1]
    output.write(line[0] + '(')
    for char in line[2:-1]:
        if re.match(r'[\d,]', char):
            output.write(char)
        else:
            output.write(sets[char])
    output.write(')\n')
output.close()

相关文档: open()re

设线为输入文件的行。 如果所有参数都是整数或函数名,则以下代码将起作用

funcs = {}
for line in lines:
    match = re.search( '(.*)\((.*)\)', line)
    if not match:
        raise RuntimeError('Line does not match expectation')
    function_name = match.group(1)
    parameters = map(str.strip, match.group(2).split(','))
    parameter_list = []
    for parameter in parameters:
        try:
            parameter_list.append(int(parameter))
        except ValueError:
            parameter_list.extend( funcs.get(parameter, []) )
    funcs[function_name] = parameter_list

for func_name, paras in sorted(funcs.items()):
    print '{function}({parameters})'.format(
        function=func_name,
        parameters=', '.join(map(str, paras))
    )

可能有很多方法可以做到这一点,但我认为这是一种简单的方法来做你想要的。

import re
import sys

def convertLine(line):
    if re.match("^\\w{1}\(.*\)$", line) is None:
        return line
    retVal = re.sub( "A", "0,1,2",line[1:])
    retVal = re.sub( "B", "0,1,2,3",retVal)
    retVal = re.sub( "C", "0,1,2,3,4,5",retVal)
    return line[0:1]+retVal

def main():
    for line in sys.stdin.read().splitlines():
        print convertLine(line)

if __name__ == "__main__":
    main()

用法:

python ReplaceProg.py < input.txt

如果你的文件是这样的

A(0,1,2)
B(A,3)
C(B,4,5)

使用python:

f = open('inpu_file.txt').readlines()
f[0] = f[0].strip()
for i,x in enumerate(f):
    if i > 0:
        f[i]=re.sub(f[i-1][0],",".join(re.findall('\d+',f[i-1])),x).strip()
print f

输出:

['A(0,1,2)', 'B(0,1,2,3)', 'C(0,1,2,3,4,5)']

我不明白...在每个备用行中,如果它在那里告诉我我可以编辑代码。

有点长但更模块化:

import re

def build_dict(fobj):
    d = dict()
    for line in fobj:
        match = re.match('^(\w)\((.*)\)', line)
        fname = match.group(1)
        fargs = match.group(2)
        d[fname] = replace(fargs, d)
    fobj.seek(0)  # Reset cursor to start of file
    return d

def replace(s, d):
    for each in d:
        if each in s:
            s = s.replace(each, d[each])
    return s

def split_paren(s):
    index = s.index('(')
    return s[:index], s[index:]

def write_replace(fobj, d):
    outname = fobj.name[:-4] + '.out'
    outfile = open(outname, 'w')
    for line in fobj:
        first, second = split_paren(line)
        second = replace(second, d)
        outfile.write(first + second)
    outfile.close()

if __name__ == '__main__':
    with open('test.txt', 'r') as f:
        d = build_dict(f)
        write_replace(f, d)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM