如何读取由正则表达式分隔的行的文件

时间:2014-12-06 21:26:56

标签: regex csv awk sed

我有一个带有嵌入换行符的csv文件。

我想做的是用不同的EOL字符重写每一行,以便其他CSV阅读器解析更简单。

为此,我知道每个新行都以正则表达式开头/ \ n" \ d +"," / - 这是换行符,引号,一些数字,另一个引号,逗号,然后另一个引用。

我可能错了,但是sed,awk和其他大多数工具都期望最后换行。是否有一个没有的Linux工具?

我的下一个想法是使用awk继续读取行并将它们推送到缓冲区,直到它找到一个以上面的表达式开头 - 然后它会写出来。

1 个答案:

答案 0 :(得分:1)

好的,让我们看看我是否理解你想要的东西。给出像

这样的csv文件
"123","foo
bar","baz"
"234","quxqux"
"345","xy
zz
y","asd"

你希望它变成像

这样的东西
"123","fooNEWLINEbar","baz"
"234","quxqux"
"345","xyNEWLINEzzNEWLINEy","asd"

然后,我可以在短时间内发出最好的声音(没有回到准备保持理智的sed文档)是这个sed脚本:

/^"[0-9]\+","/ !H
/^"[0-9]\+","/ {
  x
  s/\n/NEWLINE/g
  p
  x
  h
}
$ {
  x
  s/\n/NEWLINE/g
  p
  x
  h
}
如果代码在文件foo.sed中,则使用

,如下所示:

sed -n -f foo.sed foo.csv

<强>解释

这涉及到sed的一些较少使用的功能,因此我将简要解释两个基本机制:

  1. 模式范围
  2. 表单

    的sed命令
    /regex1/ command
    

    将命令应用于regex1可以匹配的所有行。例如,

    /^1/ s/2/3/g
    
    在以2开头的所有行中,

    3替换为1 s。 !反转匹配,所以

    /^1/ !s/2/3/g
    

    以1开头的所有行中用2替换3 s。命令可以与{}

    1. 保留缓冲区
    2. 这是sed鲜为人知但非常强大的功能之一。大多数sed命令都适用于模式空间。模式空间是写入新输入行的位置,因此命令可以对它们起作用,因此如果您单独处理行,则此机制对您来说是透明的。此外,sed有一个保持缓冲区,您可以保留以前的输入,因为您以后需要它。只有少数命令可用于保持缓冲区;其中三个是我们感兴趣的:hHxh将模式空间的当前内容(通常是刚刚写入的输入行)复制到保持缓冲区。 H将模式空间附加到保持缓冲区。 x交换模式空间的内容并保留缓冲区。

      逐块获取脚本:

      /^"[0-9]\+","/ !H
      

      这适用于"number"," H命令开头的所有行。这意味着这些行被附加到保持缓冲区。

      /^"[0-9]\+","/ {
        x
        s/\n/NEWLINE/g
        p
        x
        h
      }
      

      这适用于"number","命令块开头的所有行。那就是:

      • 交换模式空间并保留缓冲区
      • 使用NEWLINE
      • 替换模式空间中的换行符(以前是保留缓冲区)
      • 打印那些东西
      • 交换回来(模式空间现在又是新的输入行)
      • 将模式空间写入保持缓冲区,覆盖之前的内容

      最后,

      $ {
        x
        s/\n/NEWLINE/g
        p
        x
        h
      }
      

      对最后一行输入做同样的事情,因此CSV的最后一条逻辑行不会丢失。

      这意味着&#34;逻辑行的所有部分&#34; CSV的组合在保持缓冲区中,当检测到下一个的开始时,组装的线被适当地修剪并打印。