【问题标题】:Parsing a colon-separated values with broken quotes in bash在bash中用破引号解析冒号分隔的值
【发布时间】:2016-09-12 15:20:21
【问题描述】:

我有一个以冒号分隔的文件cik.coleft.c,如下所示:

!J INC:0001438823:
#1 A LIFESAFER HOLDINGS, INC.:0001509607:
#1 ARIZONA DISCOUNT PROPERTIES LLC:0001457512:
#1 PAINTBALL CORP:0001433777:
$ LLC:0001427189:
& S MEDIA GROUP LLC:0001447162:
&TV COMMUNICATIONS INC.:0001479357:
'MKTG, INC.':0000886475:
11:11 CAPITAL CORP.:0001463262:

这是一个两列csv,其中分隔逗号被冒号替换。同时,单引号用逗号转义值,而不是用冒号(分隔符)转义值。

但是第一列包含冒号,这会破坏解析器。所以当我尝试将cik.coleft.c 转换为普通的csv...

curl -o cik.coleft.c 'https://www.sec.gov/edgar/NYU/cik.coleft.c'

in2csv --format 'csv' -d ':' -q "'" -e 'latin1' cik.coleft.c > cik.coleft.csv

...我得到四列或更多列。

我尝试阅读带有sed 的行,但没有成功。

如何将其转换为合适的两列表?

【问题讨论】:

  • 你能选择一个不会与11:11之类的东西冲突的不同分隔符吗?
  • 那么,唯一不正确的冒号是最后一行的11:11
  • 您(或创建该文件的任何人)在没有重新分析每个字段的引用要求的情况下替换了分隔符,从而破坏了格式。天真地更改“X”分隔值文件中的分隔符会破坏信息,从而导致这种歧义。 (这对你没有帮助,我知道,但这是对未来的一个教训。如果其他人破坏了文件,你可以合法地投诉。)

标签: bash parsing csv sed


【解决方案1】:

您可以使用awk 并使用subtrlength 进行一些字符串操作:

awk 'BEGIN{OFS="|"}{col1=substr($0,1,length($0)-12);col2=substr($0,length($0)-10, 10);print col1,col2}' yourfile

这会将输出字段分隔符 OFS 设置为管道 |。它使用substr()length() 描绘了两列。通过从第 1 个字符开始到记录末尾前 12 个字符结束,可以找到第 1 列。第 2 列是通过在记录末尾前 10 个字符开始并在其后抓取 10 个字符来找到的。

测试输出:

$ awk 'BEGIN{OFS="|"}{col1=substr($0,1,length($0)-12);col2=substr($0,length($0)-10, 10);print col1,col2}' test
!J INC|0001438823
#1 A LIFESAFER HOLDINGS, INC.|0001509607
#1 ARIZONA DISCOUNT PROPERTIES LLC|0001457512
#1 PAINTBALL CORP|0001433777
$ LLC|0001427189
& S MEDIA GROUP LLC|0001447162
&TV COMMUNICATIONS INC.|0001479357
'MKTG, INC.'|0000886475
11:11 CAPITAL CORP.|0001463262

这只是因为您的第二个字段似乎总是一个 10 位数字。如果文件的其他部分有所不同,那么您将不得不走不同的路线。

【讨论】:

    【解决方案2】:

    你可以从后面接近它

    $ rev file | sed 's/:/~/3' | rev | column -ts:
    
    !J INC                              0001438823
    #1 A LIFESAFER HOLDINGS, INC.       0001509607
    #1 ARIZONA DISCOUNT PROPERTIES LLC  0001457512
    #1 PAINTBALL CORP                   0001433777
    $ LLC                               0001427189
    & S MEDIA GROUP LLC                 0001447162
    &TV COMMUNICATIONS INC.             0001479357
    'MKTG, INC.'                        0000886475
    11~11 CAPITAL CORP.                 0001463262
    

    知道有两列,我们反转该行并将: 的第三个实例替换为~

    如果你有不止一个额外需要替换,使用 gnu sed 使用 g3 而不是 3 后缀。

    【讨论】:

      【解决方案3】:

      TXR中的可能解决方案:

      策略是通过数据进行匹配,但线条从左到右颠倒。为此,我们使用@(next ...) 将输入重定向到一个懒惰的:list 行,由lazily mapping 通过(get-lines) 函数产生(get-lines) 的输出。以下为fixcolon.txr

      @(next :list @[mapcar* reverse (get-lines)])
      @(repeat)
      @  (assert)
      @  (cases)
      :@right:'@left'
      @  (or)
      :@right:@left
      @  (end)
      @  (do (put-line (reverse
                         (if (break-str left ":")
                           `:@right:'@left'`
                           `:@right:@left`))))
      @(end)
      

      基本上只有两种情况:我们有一个单引号,或者我们没有。如果存在单引号,我们希望删除它们,并且仅当字段包含冒号时才重新添加它们。

      以下额外的行已添加到数据中:

      11:11 CA:PI:TAL CORP.:0001463262:
      

      输出:

      $ txr fixcolon.txr < data
      !J INC:0001438823:
      #1 A LIFESAFER HOLDINGS, INC.:0001509607:
      #1 ARIZONA DISCOUNT PROPERTIES LLC:0001457512:
      #1 PAINTBALL CORP:0001433777:
      $ LLC:0001427189:
      & S MEDIA GROUP LLC:0001447162:
      &TV COMMUNICATIONS INC.:0001479357:
      MKTG, INC.:0000886475:
      '11:11 CAPITAL CORP.':0001463262:
      '11:11 CA:PI:TAL CORP.':0001463262:
      

      多余的引用已经消失 MKTG, INC.。在11:11 ... 字段周围引入了引号。 (没有尝试处理嵌入的单引号,因为示例数据和问题文本没有指定或暗示任何要求)。

      @(assert) 确保模式匹配在与后面的情况不匹配的数据上出现异常。该指令有效地表示“我之后的一切都匹配,否则我扔!”没有它,@(repeat) 指令将跳过不匹配的数据。 (如果使用:gap 0 告诉不要跳过它,它将在第一个不匹配的行处停止。然后为了捕捉这个问题,我们需要一个我们在 EOF 的断言)。

      $ txr fixcolon.txr
      foo:bar:
      junk!
      [Ctrl-D][Enter]
      foo:bar:
      txr: unhandled exception of type assert:
      txr: (fixcolon.txr:3) assertion (at var:2)
      txr: during evaluation at fixcolon.txr:3 of form (assert)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多