【问题标题】:How to replace one field of a line by another line in awk/sed/python?如何在awk/sed/python中用另一行替换一行的一个字段?
【发布时间】:2015-01-02 08:24:07
【问题描述】:

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,将函数名视为键,将其参数视为值。实现起来并不容易。

【问题讨论】:

  • 这个……在输入文件里也有????

标签: python regex bash awk sed


【解决方案1】:

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 的执行定义。

【讨论】:

    【解决方案2】:

    有点长但更模块化:

    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)
    

    【讨论】:

      【解决方案3】:

      如果你的文件是这样的

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

      我不明白……在每一行中,如果有的话告诉我我可以为此编辑代码。

      【讨论】:

        【解决方案4】:

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

        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
        

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            【解决方案6】:

            这里有一个 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。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-10-07
              • 2017-07-12
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多