如何删除 csv 中的新行字符? csv 以文件分隔符 (\u001C) 作为分隔符

如何删除 csv 中的新行字符? csv 以文件分隔符 (\u001C) 作为分隔符

我有一个包含 150 多列的 CSV 文件,其中文件分隔符符号作为字段分隔符。问题在于其中一列获得换行符。为此,我想删除这些。

输入数据

在此输入图像描述

输出数据

在此输入图像描述

答案1

用于在输出中hd显示 FS 字符(十六进制):1c

$ perl -0777 -pe 's/^(\d{3}.*)\n/$1/mg' input.txt | hd
00000000  30 30 31 1c 42 61 6b 65  72 20 53 74 2e 4c 6f 6e  |001.Baker St.Lon|
00000010  64 6f 6e 1c 33 1c 34 1c  37 0a 30 30 32 1c 50 65  |don.3.4.7.002.Pe|
00000020  6e 6e 79 20 4c 61 6e 65  4c 69 76 65 72 70 6f 6f  |nny LaneLiverpoo|
00000030  6c 1c 38 38 1c 35 1c 37  0a                       |l.88.5.7.|
00000039

如果没有hd,输出看起来像这样( FS 字符不可见但仍然存在,因此它们将要-i如果它被重定向到另一个文件,或者如果使用“就地编辑”选项,则位于输出中):

$ perl -0777 -pe 's/^(\d{3}.*)\n/$1/mg' input.txt   
001Baker St.London347
002Penny LaneLiverpool8857

在这两种情况下,此 Perl 脚本会立即读取整个文件 ( -0777),并捕获每个“行”(以三位数字开头的字符序列,直到但不包括下一个换行符)并将其替换为捕获的文本 (没有换行符)。简而言之,它从任何以三位数字开头的“行”中删除换行符。

$1如果您希望用空格替换不需要的换行符,而不是直接删除它们,请在 RHS后面添加一个空格。或者\x1c如果您希望它将换行符更改为 FS 字符。

搜索s///和替换操作使用m(“多行字符串”)和g(“全局”)正则表达式修饰符。 g对于几个使用正则表达式的工具(包括 sed)来说很常见,并导致正则表达式进行“全局”重复匹配,但m特定于 perl:

来自man perlre(搜索“修饰符”部分):

m将匹配的字符串视为多行。也就是说,将 and 从匹配字符串第一行的开头和最后一行的结尾更改^$匹配字符串中每行的开头和结尾。

注意 1:此脚本不关心“字段”分隔符是什么。它根本不查找或使用字段。如果字段分隔符是空格、制表符、冒号或其他任何内容(当然换行符除外),它也同样有效。

注意 2:如果不需要的换行符后面的任何字段以三位数字开头,则此方法将不起作用 - 例如123 London。处理这个问题需要一个更复杂的脚本,一个能够解析和计算输入中的字段的脚本。

答案2

您可以使用awk

awk '{
  while (NF < 5  && getline cmp) { $0=$0"<br>"cmp }
  if (NF > 5) {
    print "#ERROR"
    count++
  }
  print
}
END{
  if (count) {
    print "FAILED "count" lines" > "/dev/stderr"
    exit 8
  }
}' FS=$'\x1c'
  • awk非常擅长解析具有指定分隔符的字段
  • NF告诉当前行中的字段数
  • 您希望换行符始终出现在第二个字段中,然后您知道何时必须完成该行;只需阅读下一行并粘贴即可;也许用胶水标记<br>比用空格标记更好,这样就不会丢失信息。
  • 如果换行符可以出现在该行的最后一个字段中,那么它会变得更加困难,但您的样本是安全的;不管怎样,这个脚本捕获了错误

亚斯塔?

答案3

使用(以前称为 Perl_6)

raku -e 'slurp.split("\x1C").join("\t").put;'  

输入示例(制表符分隔):

~$ cat FS_test.txt
001 Baker St.
London  3   4   7
002 Penny Lane
Liverpool   88  5   7

~$ cat FS_test.txt | xxd
00000000: 3030 3109 4261 6b65 7220 5374 2e0a 4c6f  001.Baker St..Lo
00000010: 6e64 6f6e 0933 0934 0937 0a30 3032 0950  ndon.3.4.7.002.P
00000020: 656e 6e79 204c 616e 650a 4c69 7665 7270  enny Lane.Liverp
00000030: 6f6f 6c09 3838 0935 0937 0a              ool.88.5.7.

将制表符转换为FS(使用 MacOS 的查看十六进制xxd):

~$ raku -e 'slurp.split("\t").join("\x1C").put;' baker_st_FS_test.txt | xxd
00000000: 3030 311c 4261 6b65 7220 5374 2e0a 4c6f  001.Baker St..Lo
00000010: 6e64 6f6e 1c33 1c34 1c37 0a30 3032 1c50  ndon.3.4.7.002.P
00000020: 656e 6e79 204c 616e 650a 4c69 7665 7270  enny Lane.Liverp
00000030: 6f6f 6c1c 3838 1c35 1c37 0a0a            ool.88.5.7..

将制表符转换为-FS并再次转换回来(FS-to-tabs):

~$ cat FS_test.txt | raku -e 'slurp.split("\t").join("\x1C").put;' | raku -e 'slurp.split("\x1C").join("\t").put;'
001 Baker St.
London  3   4   7
002 Penny Lane
Liverpool   88  5   7


~$ cat FS_test.txt | raku -e 'slurp.split("\t").join("\x1C").put;' | raku -e 'slurp.split("\x1C").join("\t").put;' | xxd
00000000: 3030 3109 4261 6b65 7220 5374 2e0a 4c6f  001.Baker St..Lo
00000010: 6e64 6f6e 0933 0934 0937 0a30 3032 0950  ndon.3.4.7.002.P
00000020: 656e 6e79 204c 616e 650a 4c69 7665 7270  enny Lane.Liverp
00000030: 6f6f 6c09 3838 0935 0937 0a0a 0a         ool.88.5.7...

请注意,每次拆分/合并往返都会在文件末尾添加一个额外的空行。通过.subst(/\n/, :nth(*))在 Final 之前插入例行调用来摆脱这些问题.put。或者通过.trim-trailing在 slurped 文件上运行来消除所有尾随空格。 (另外,感谢@cas 提出的十六进制查看器想法)。


附录:Raku 的trans后期例程也有效:

raku -e 'slurp.trans("\x1C" => "\t").put;'

https://raku.org

相关内容