【问题标题】:Using sed to remove embedded newlines使用 sed 删除嵌入的换行符
【发布时间】:2014-12-09 19:58:04
【问题描述】:

什么是 sed 脚本,它将删除 "\n" 字符,但前提是它位于 "" 字符(分隔字符串)内,而不是实际位于(虚拟)行末尾的 \n? 比如我要转这个文件

"lalala","lalalslalsa"
"lalalala","lkjasjdf
asdfasfd"
"lalala","dasdf"

(第 2 行有一个嵌入的 \n )到这个

"lalala","lalalslalsa"
"lalalala","lkjasjdf \\n asdfasfd"
"lalala","dasdf"

(第 2 行和第 3 行现在连在一起了,真正的换行符被替换为字符串 \\n (或任何其他容易识别的字符串,我不挑剔))

我不想像之前的问题一样删除所有其他换行符,我也不想删除所有换行符,只是那些在引号内的换行符。我不喜欢 sed,如果 awk 可以工作,那也没关系。

正在操作的文件太大,无法一次全部放入内存。

【问题讨论】:

    标签: sed awk


    【解决方案1】:

    sed 是用于在单行上进行简单替换的出色工具,但对于其他任何内容,您都应该使用 awk。例如:

    $ cat tst.awk
    {
        if (/"$/) {
            print prev $0
            prev = ""
        }
        else {
            prev = prev $0 " \\\\n "
        }
    }
    
    $ awk -f tst.awk file
    "lalala","lalalslalsa"
    "lalalala","lkjasjdf \\n asdfasfd"
    "lalala","dasdf"
    

    以下是我最初的答案,但在看到@NeronLeVelu 仅在行尾测试报价的方法后,我意识到我这样做的方式过于复杂。您可以将下面的gsub(/"/,"&") % 2 替换为/"$/,它的工作原理相同,但上面的代码是相同功能的更简单实现,现在将处理嵌入的转义双引号,只要它们不在末尾一行。

    $ cat tst.awk
    { $0 = saved $0; saved="" }
    gsub(/"/,"&") % 2 { saved = $0 " \\\\n "; next }
    { print }
    
    $ awk -f tst.awk file
    "lalala","lalalslalsa"
    "lalalala","lkjasjdf \\n asdfasfd"
    "lalala","dasdf"
    

    上面一次只在内存中存储 1 个输出行。它只是不断地从输入行构建一个输出行,而该输出行中的双引号数为奇数,然后当它最终包含偶数个双引号时打印输出行。

    如果您可以在引用的字符串中将双引号转义为\",而不是"",它将失败,但是您没有在发布的示例输入中显示这一点,所以希望您没有这种情况。如果您遇到这种情况,您需要编写/使用真正的 CSV 解析器。

    【讨论】:

    • 内部\" 的好评。一种方法是在操作之前翻译它,然后再翻译回来,这样代码在之间仍然是相同的
    【解决方案2】:
    sed -n ':load
    /"$/ !{N
          b load
          }
    :cycle
    s/^\(\([^"]*"[^"]*"\)*\)\([^"]*"[^"]*\)\n/\1\3 \\\\n /
    t cycle
    p' YourFile
    
    • 在工作缓冲区中加载行,直到找到关闭行(以" 结尾)或到达终点
    • 用转义版本的新行替换从文件开头开始的" 之间的任何其他字符(实际上用起始字符串替换起始字符串 + \n 并转义新行)
    • 如果发生任何替换,请重试另一个(:cyclet cycle
    • 打印结果
    • 继续直到文件结束

    感谢@Ed Morton 关于转义新行的评论

    【讨论】:

    • @Larry Pieniazek 提到,输入文件很大,所以在缓冲区中加载整个文件不是一个好主意。其次,如果在三行中换行,那么您的代码仍然只合并两行。
    • 适应大文件(一次只能处理“打开”字符串)。如果找到至少 1 条断线,则合并该行,因此如果 1000 条断线在同一个字符串中,合并后,只有 1 行。这就是我使用t cycle 的原因
    • 哎呀,对。我忘记在测试后更换转义的新行。我修改代码
    • 简单地测试以双引号结尾的行比我做的方式(测试累积行中的奇数双引号)要好得多。好的! +1 或方法(当然,由于所需代码与 awk 的相对复杂性,我仍然不会在 sed 中这样做)。
    • 对于 sed vs awk,在这种情况下,这个大 s/// 让我去 awk(与这种模式上的 awk 相比,任何修改的代码错误风险都很大)和 perf 是当然也是 awk 的一个要点,尤其是在大文件上
    猜你喜欢
    • 2012-05-24
    • 2018-01-21
    • 1970-01-01
    • 2015-02-15
    • 2016-03-19
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 2019-12-01
    相关资源
    最近更新 更多