简体   繁体   English

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

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

input.txt input.txt中

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

If the first parameter of a function is not equal 0 but corresponding to a function name, I want to replace it with all of the corresponding function's parameters (eg to replace the first parameter 'A' in function B above with all parameters of function A). 如果函数的第一个参数不等于0但对应于函数名,我想用所有相应函数的参数替换它(例如,将上面函数B中的第一个参数'A'替换​​为函数A的所有参数)。 That is to expect 这是期待的

output.txt output.txt的

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

How can we do this with awk/sed or python? 我们怎么能用awk / sed或python做到这一点?

EDIT: 编辑:

One idea I have is to store the function name as variables and its parameters as values in bash. 我的一个想法是将函数名称作为变量存储,将其参数作为值存储在bash中。 In python, we may use dict, and consider function names as keys, and its parameters as values. 在python中,我们可以使用dict,并将函数名称视为键,将其参数视为值。 The implementation is not that easy. 实施并不那么容易。

Awk AWK

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

Where sub(/^[^,]+/, val[a[1]], $2) is used to match the first parameter in $2 and replace it with the value of val[a[1]] which is defined by the execution of val[$1] = $2 on previous lines. 其中sub(/^[^,]+/, val[a[1]], $2)用于匹配$2中的第一个参数,并将其替换为val[a[1]]的值,该值由在前一行执行val[$1] = $2

Here's a solution in Python: 这是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()

Relevant documentation: open() , re . 相关文档: open()re

Let lines be the lines of the input file. 设线为输入文件的行。 The following code will work if all parameters are integers or a functionname 如果所有参数都是整数或函数名,则以下代码将起作用

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))
    )

There are probably a ton of ways to do this but I think this is a simple way to do what you want. 可能有很多方法可以做到这一点,但我认为这是一种简单的方法来做你想要的。

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()

usage: 用法:

python ReplaceProg.py < input.txt

if your file is like this 如果你的文件是这样的

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

using python: 使用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

output: 输出:

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

i don't understand that ... in every alternate line, if its there tell me i can edit the code for that. 我不明白...在每个备用行中,如果它在那里告诉我我可以编辑代码。

Kinda long but more modular: 有点长但更模块化:

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