简体   繁体   中英

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)

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). That is to expect

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?

EDIT:

One idea I have is to store the function name as variables and its parameters as values in bash. In python, we may use dict, and consider function names as keys, and its parameters as values. The implementation is not that easy.

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.

Here's a solution in 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 .

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:

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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