如何删除字符串中的\n

如何删除字符串中的\n

我有一个制表符分隔的文本文件,其中带有字符串的第 23 列中有 \n ,这导致它断到下一行。

我在 vi 中打开文本文件并启用空白字符,我可以看到 DESCR2 字段中的值有破坏字符串的空行。

该字符串包含在制表符分隔的字符内,我试图删除 \n 并将字符串连接到 ABC 123,同时仍在 1 field 中。

我已经尝试过tr -d '\n' < file.txt,但这会使所有行变成 1 行。我只想从该列中删除 \n\n 。

我也尝试过sed 's/\n\n//' file.txt但是没有效果。我可以在 vi 中搜索并替换 \n\n 但无法使用 sed 获得相同的结果。

例子:

\t"ABC\n
\n
123"\t

期望的输出:

\t"ABC 123"\t

答案1

您似乎有一个格式正确的 CSV 文件,该文件使用制表符作为字段分隔符。只要正确引用这些字段,就可以在字段中嵌入换行符,您显示的示例就是这样。任何 CSV 解析器在读取您的数据时都不会出现问题。

如果您想删除这些换行符,您可以使用 CSV 解析器,例如csvkit

我将处理一个如下所示的示例文件:

$ cat -t file.csv
col1^Icol2^Icol3
col1^I"ABC

123"^Icol3
col1^Icol2^Icol3

每个^I都是制表符。第二行的第二个字段包含两个连续的换行符,我们希望安全地将它们替换为单个空格字符。

我正在使用csvjsonfrom csvkit,它将 CSV 数据转换为 JSON 文档。这使得使用 修改数据变得稍微容易一些jq,它也可以用于将数据转回 CSV 格式:

$ csvjson -t -H file.csv | jq -r '.[] | [ .[] | values |= gsub("\n\n";" ") ] | @csv'
"col1","col2","col3"
"col1","ABC 123","col3"
"col1","col2","col3"

此处使用的命令csvjson将 CSV 文件的每一行转换为 JSON 对象。该-t选项告诉工具输入使用制表符作为分隔符,并且-H我们告诉它没有列标题。

JSON 对象被放入一个数组中并通过读取来jq提取值(数据将分配给abc等键,因为原始 CSV 文件没有标题,或者至少没有问题中提到的标题)并应用简单的替换,使用gsub()空格替换每对连续的换行符。

gsub()显然,您可以更改上面使用的正则表达式,\n+使其用单个空格字符替换任何连续的换行符。

然后,操作员@csv接收一组数组形式的数据,这些数据被格式化为 CSV 输出。

csvformat您是否想要将默认字段分隔符从逗号更改回制表符,使用其-T(对于制表符分隔输出)和-H(CSV 输入中没有标题)选项通过管道传输结果:

$ csvjson -t -H file.csv | jq -r '.[] | [ .[] | values |= gsub("\n\n";" ") ] | @csv' | csvformat -T -H
col1    col2    col3
col1    ABC 123 col3
col1    col2    col3

csvformat会自动引用需要引用的字段。

csvformat工具也是csvkit.


作为参考,由 创建的中间 JSON 文档csvjson如下所示(由 进行美化jq):

[
  {
    "a": "col1",
    "b": "col2",
    "c": "col3"
  },
  {
    "a": "col1",
    "b": "ABC\n\n123",
    "c": "col3"
  },
  {
    "a": "col1",
    "b": "col2",
    "c": "col3"
  }
]

答案2

GoCSV 可以做到这一点。

将 TSV 转换为 CSV 并替换换行符

我从看起来像这样的 TSV 文件开始,尝试模拟您的数据:

+--------+--------+--------+--------+--------+
| Col21  | Col22  | DESCR2 | Col24  | Col25  |
+--------+--------+--------+--------+--------+
| data21 | data22 | ABC    | data24 | data25 |
|        |        |        |        |        |
|        |        | 123    |        |        |
+--------+--------+--------+--------+--------+

第一步是将 TSV 转换为 CSV,这是所有 GoCSV 命令所使用的格式。我还在末尾添加了一个新列,其中包含 DESC2 的值并替换了换行符。 -n是个姓名新专栏的-t是 SPRIG模板具有replace我们需要的函数(.DESCR2 | replace读起来像“将 DESCR2 列放入替换函数中”):

gocsv delim   \
    -i "\t"   \
    -o ","    \
    input.tsv | 
  gocsv add                               \
    -n DESCR2_replaced                    \
    -t '{{ .DESCR2 | replace "\n" " " }}' \
  > replaced.csv

替换.csv

+--------+--------+--------+--------+--------+-----------------+
| Col21  | Col22  | DESCR2 | Col24  | Col25  | DESCR2_replaced |
+--------+--------+--------+--------+--------+-----------------+
| data21 | data22 | ABC    | data24 | data25 | ABC  123        |
|        |        |        |        |        |                 |
|        |        | 123    |        |        |                 |
+--------+--------+--------+--------+--------+-----------------+

换入新列并重命名为旧列

在 _replaced 列中对数据进行标准化后,我将“选择出”旧的 DESCR2 并“选择”新的 DESCR2_replaced 代替它;然后改名DESCR2_替换回 DESCR2。在我的示例中,我只有 6 列,因此-C 柱子索引与您的 23+ 列文件中的索引不同:

gocsv select     \
    -c 1-2,6,4-5 \
    replaced.csv |
  gocsv rename    \
    -c 3          \
    -names DESCR2 \
  > final.csv

最终.csv

+--------+--------+----------+--------+--------+
| Col21  | Col22  | DESCR2   | Col24  | Col25  |
+--------+--------+----------+--------+--------+
| data21 | data22 | ABC  123 | data24 | data25 |
+--------+--------+----------+--------+--------+

转换回 TSV

gocsv delim   \
    -i ","    \
    -o "\t"   \
    final.csv \
  > final.tsv

一条大管道

gocsv delim                                \
    -i "\t"                                \
    -o ","                                 \
    input.tsv                              \
| gocsv add                                \
    -n DESCR2_replaced                     \
    -t '{{ .DESCR2 | replace "\n" " " }}'  \
| gocsv select                             \
    -c 1-2,6,4-5                           \
| gocsv rename                             \
    -c 3                                   \
    -names DESCR2                          \
| gocsv delim                              \
    -i ","                                 \
    -o "\t"                                \
> final.tsv

答案3

您是否尝试过使用:sed ':a;N;$!ba;s/\\n\n/ /g' file.txt

我发现答案详细说明了如何使用 sed 删除换行符,并在\\n其前面添加了一个附加反斜杠来转义特殊字符。

答案4

一次简单的 sed 运行在其模式空间中的任何一次都只包含一行,这就是您的 sed 语法不起作用的原因。一个(类似,如果不重复)问题有一个答案,解释如何使用 sed 处理多行编辑这里。 TLDR 是它很糟糕并且语法很痛苦

同样, tr 也会失败,因为它在任何时候都只查看一行。

在我看来,处理多行的最简单方法是使用 perl:

perl -0777 -pe 's/\n\n/ /igs' file.txt

其中 -0777 告诉 perl 匹配整个文件,而 -pe 只是查找和替换

此版本将使用 -i 进行内联编辑

perl -0777 -pe 's/\n\n/ /igs' -i file.txt

编辑:如果您打算用显示的特殊字符进行替换,您可能需要在正则表达式中正确转义 \n

相关内容