首页 > 解决方案 > 在 Python 中使用 awk 在文件中插入文本

问题描述

我在使用 Python 插入一些文本时遇到了一些麻烦。我有一个文件,Package.swift内容如下:

  targets: [
    .target(
      name: "LibCore",
      path: "lib/core/"
    ),
    .target(
      name: "LibAppData",
      dependencies: ["LibCore"],
      path: "lib/appdata/",
      swiftSettings: [.define("appdata")]
    ),

我想.target()在开口下方插入一个新的targets: [

awk在 zsh 中使用:

    awk '{print} /\.target\(/ && !n {print "      name: \"{full_name}\",\n      dependencies: \[\"LibCore\"\],\n      path: \"lib\/{short_name}\/\",\n      swiftSettings: [.define(\"{short_name}\")]\n    ),\n    .target("; n++}' Package.swift > Package-new.swift && mv Package-new.swift Package.swift

我在 Python 中尝试过以下操作:

  1. subprocess.call([f"awk '{print} /\\.target\\(/ && !n {{print "      name: "{full_name}\",\n      dependencies: \\[\"LibCore\"\\],\n      path: \"lib\\/{short_name}\\/\",\n      swiftSettings: [.define(\"{short_name}\")]\n    ),\n    .target("; n++ "}}' Package.swift > Package-new.swift && mv Package-new.swift Package.swift"], shell=True) 
    
  2. subprocess.call(['awk.exe', '{print} /\\.target\\(/ && !n {print "      name: \"{full_name}\",\n      dependencies: \\[\"LibCore\"\\],\n      path: \"lib\\/{short_name}\\/\",\n      swiftSettings: [.define(\"{short_name}\")]\n    ),\n    .target("; n++}', 'Package.swift'])
    
  3.     tmp=tempfile.mkstemp()
        with open("Package.swift") as fd1, open(tmp[1],'w') as fd2:
            for line in fd1:
                line = line.replace("\\.target\\(",f"      name: \"{full_name}\",\n      dependencies: \\[\"LibCore\"\\],\n      path: \"lib\\/{short_name}\\/\",\n      swiftSettings: [.define(\"{short_name}\")]\n    ),\n    .target(")
                fd2.write(line)
        os.rename(tmp[1],"Package.swift")
    
  4.     newtext = '''\
                name: "{full_name}\",\n      dependencies: \\[\"LibCore\"\\],\n      path: \"lib\\/{short_name}\\/\",\n      swiftSettings: [.define(\"{short_name}\")]\n    ),\n    .target(
                '''
        filename = 'Package.swift'
        for line in fileinput.input([filename], inplace=True, backup='.bak'):
            if re.match(r'\\.target\\(', line):
                sys.stdout.write(newtext.format(l=line))
            else:
                sys.stdout.write(line)
    

我还尝试了许多变体,试图逃避 {},但每次 SyntaxError: invalid syntax我尝试运行脚本时仍然得到一个。如果不是很明显,Python 不是我的第一语言

有人会知道我错过了什么吗?

谢谢!

标签: pythonpython-3.xawkinsert

解决方案


问题:

  1. 在 1 中,您错过了几个"需要转义的双引号字符。
  2. 这条线在 Python 中似乎在语法上很好,但在Python中运行 awk 总是有点恶心。但是,这是awk中的语法错误。与其他一些语言不同,Python 中的单引号字符串仍然将转义字符视为转义字符,因此,例如,'"''\"'是相同的字符串文字。

    这意味着这个例子:"name: \"{full_name}\""被转换为"name: "{full_name}""当喂给 awk 时会扰乱你的引用。

  3. 有了这个,你就走得太远了:太多的逃避。

    This:line = line.replace("\\.target\\(",从不匹配,因为您的文件不包含字符串: \.target\(

    不过,这不是语法错误,它不会做任何事情。

  4. 正如他们所说,现在你有两个问题。或者,实际上,三个问题。您的正则表达式与 (3) 中存在相同的问题,match()是在此处使用的错误调用,并且string.format不能像那样工作。

    当 re 包尝试使用它时,错误转义的正则表达式应该给你这个错误:

    re.error: missing ), unterminated subpattern at position XX(其中 XX 是行号)

    如果您从正则表达式中删除多余的转义,您会得到:\.target\(. 如果Package.swift文件没有缩进,你可以这样做,但它确实有缩进,并且只有当模式从字符串的开头re.match匹配时,函数才会得到匹配。您想要, 匹配任何地方。或者,您可以更改模式以匹配字符串前任意数量的空白字符,如下所示:re.search.target[ \t]*\.target\(

    所以,最后一个问题:f-strings 从它们所在的范围中拉入变量,但string.format没有:每个值都需要作为字典的值传入,而l=line您在此处指定的...不什么都不做?最重要的是,因为您替换了.target(字符串而不是更改或重写它,所以您的输出文件在语法上不是有效的 Swift。

在某些情况下,我觉得您错过了有关您进行的库调用的文档的重要部分?如果您正在处理其他问题,Python 官方文档很好,而且很有帮助!

此外,您应该从这些片段中看到的错误消息完全不同(在一种情况下,根本没有错误)。如果您更改了这么多并且您看到的错误消息并没有完全不同,那么问题不在这部分代码中。


推荐阅读