【问题标题】:How can I join lines in a CSV file when one of the fields has a newline?当其中一个字段有换行符时,如何在 CSV 文件中加入行?
【发布时间】:2008-11-10 18:14:58
【问题描述】:

如果我有一个逗号分隔的文件,如下所示:

富,酒吧,n ,A B C D 一二三 ,A B C D

我想加入\n, 来制作这个:

foo,bar,n,a,bc,d 一、二、三、a、bc、d

什么是正则表达式技巧?我以为if (/\n,/) 会抓住这一点。

另外,对于 UTF-8 编码的文件,我需要做一些特殊的事情吗?

最后,Groovy 中的解决方案也会有所帮助。

【问题讨论】:

  • 一般情况下,一行的第一个字段可以为空,在这种情况下,它可以以逗号开头。那么,你怎么知道什么时候需要合并这些行呢?
  • 额外的换行符是字段值的一部分还是包装文本的工具的结果?

标签: perl groovy csv newline


【解决方案1】:

您应该使用Text::CSV_XS 而不是自己执行此操作。它支持嵌入在记录中的换行符以及 Unicode 文件。您需要在创建解析器时指定正确的选项,因此请务必仔细阅读文档。

【讨论】:

    【解决方案2】:

    这对我有用:

    open(F, "test.txt") or die;
    undef $/;
    $s = <F>;
    close(F);
    $s =~ s/\n,/,/g;
    print $s;
    
    $ cat test.txt
    foo,bar,n
    ,a,bc,d
    one,two,three
    ,a,bc,d
    $ perl test.pl 
    foo,bar,n,a,bc,d
    one,two,three,a,bc,d
    

    【讨论】:

    • 这不适用于第一个字段为空的记录(并且该行以逗号开头)。通常你必须阅读一行,看看它是否有正确数量的字段,然后决定下一步做什么。
    • 没错,但我选择回答最初的问题(“什么是正则表达式技巧?”),而不是猜测在初始字段为空的情况下可能需要做什么。
    【解决方案3】:

    这是一个时髦的版本。根据要求,这可能无法捕捉到一些细微差别(例如可以在其中包含逗号的带引号的字符串)。如果换行符可以出现在字段的中间而不是总是出现在末尾,那么它也必须进行调整。

    def input = """foo,bar,n
    ,a,bc,d
    one,two,three
    ,a,bc,d"""
    
    def answer = (input =~ /(.*\n?,){5}.*(\n|$)/).inject ("") { ans, match  ->
        ans << match.replaceAll("\n","") << "\n"
    }
    
    assert answer.toString() == 
    """foo,bar,n,a,bc,d
    one,two,three,a,bc,d
    """
    

    【讨论】:

      【解决方案4】:

      这可能太简单了(或者不能很好地处理一般情况),

      def input = """foo,bar,n
      ,a,bc,d
      one,two,three
      ,a,bc,d"""
      
      def last
      input.eachLine {
          if(it.startsWith(',')) {
              last += it;
              return;
          }
          if(last)
              println last;
          last = it
      }
      println last
      

      发射;

      foo,bar,n,a,bc,d
      one,two,three,a,bc,d
      

      【讨论】:

        【解决方案5】:

        这主要是为了回答您的 UTF-8 编码问题。

        根据具体的编码,您可能还需要查找空字节。如果上述建议对您不起作用,将 's/\n,/,/g' 替换为 's/\c@?\n(\c@?,)/$1/g' 可能会在不破坏编码的情况下工作,尽管迭代地执行它可能更安全(将 's/\c@?\n(\c@?,)/$1/' 应用于每一行,而不是将它们连接起来并全局应用)。这确实是一个 hack,不能替代真正的 unicode 支持,但如果您只需要快速修复,或者您对编码有保证,它可能会有所帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-01-31
          • 2015-08-18
          • 2012-12-29
          • 2011-07-25
          • 2012-08-27
          • 1970-01-01
          • 2013-10-19
          相关资源
          最近更新 更多