识别和替换给定文本文件中的选择性空间
Posted
技术标签:
【中文标题】识别和替换给定文本文件中的选择性空间【英文标题】:Identify and replace selective space inside given text file 【发布时间】:2020-11-15 21:21:15 【问题描述】:我是 sed 及其功能的新手。我需要在文件内容如下的文件中选择性地用“,”替换空格。我不想替换 "" 内的空格,但所有其他空格都需要替换。
文件内容
my data "this is my very first encounter with sed" "valuable" - - "c l e a r"
使用过的图案 使用 sed 将空格替换为 "," - Patten 是 's/ /,/g'
实际输出
my,data,"this,is,my,very,first,encounter,with,sed",,"valuable",-,-,"c,l,e,a,r"
预期输出
my,data,"this is my very first encounter with sed",,"valuable",-,-,"c l e a r"
【问题讨论】:
虽然在 sed 中是“可能的”,但不要这样做。用另一种更简单的编程语言编写适当的 CSV 解析器。 【参考方案1】:以下带有 cmets 的 sed 脚本,输入来自 bash 此处的字符串:
<<<'my data "this is my very first encounter with sed" "valuable" - - "c l e a r"' sed -E '
# Split input with each character on its own line
s/./&\n/g;
# Add a newline on the end to separate output from input
s/$/\n/;
# Each line has one character
# Add a leading character that stores "state"
# There are two states available - in quoting or not in quoting
# The state character is space when we are not in quotes
# The state character is double quote when we are in quotes
s/^/ /;
# For each character in input
:again;
# Substitute a space that is not in quotes for a comma
s/^ / ,/
# When quotes is encountered and we are not in quotes
/^ "/
# Change state to quotes
s//""/
b removed_quotes
;
# When quotes is encountered and we are in quotes
# then we are no longer in quotes
s/^""/ "/
; : removed_quotes
# Preserve state as the first character
# Add the parsed character to the output on the end
# Preserve the rest
s/^(.)(.)\n(.*)/\1\3\2/;
# If end of input was not reached, then parse another character.
/^.\n/!b again;
;
# Remove the leading state character with the newline
s///;
'
输出:
my,data,"this is my very first encounter with sed",,"valuable",-,-,"c l e a r"
还有一个oneliner,因为谁会阅读这些cmets:
sed -E 's/./&\n/g;s/$/\n/;s/^/ /;:a;s/^ / ,/;/^ "/s//""/;bq;;s/^""/ "/;:q;s/^(.)(.)\n(.*)/\1\3\2/;/^.\n/!ba;s///'
我认为s
命令替换字符串中的换行符\n
是posix 不需要的扩展。解析时可以使用另一个唯一字符代替换行符来分隔输入。无论如何,我用 GNU sed 进行了测试。
【讨论】:
wrtI think a newline ...
- 仅有 2 个具有 -E
参数的 sed 是 GNU 和 OSX/BSD,前者将与 \n
一起工作,后者不会,所以是的,它是 GNU仅限 sed。几乎可以肯定还有其他 GNU 主义。【参考方案2】:
正如 cmets 中所提到的,这更适合实际的 CSV 解析器,而不是试图使用正则表达式来拼凑一些东西——尤其是 sed
的相当基本的正则表达式。
在perl
中使用有用的Text::AutoCSV 模块(通过您的操作系统包管理器或最喜欢的CPAN 客户端安装)的单行:
$ perl -MText::AutoCSV -e 'Text::AutoCSV->new(sep_char=>" ", out_sep_char=>",")->write' < input.txt
my,data,"this is my very first encounter with sed",,valuable,-,-,"c l e a r"
【讨论】:
【参考方案3】:使用 GNU awk 进行 FPAT:
$ awk -v FPAT='[^ ]*|"[^"]+"' -v OFS=',' '$1=$1 1' file
my,data,"this is my very first encounter with sed",,"valuable",-,-,"c l e a r"
您的输入是 CSV,在这种情况下,C
表示“字符”而不是传统的“逗号”,并且所讨论的字符是空白,而您只是想将其转换为逗号分隔的 CSV .请参阅What's the most robust way to efficiently parse CSV using awk?,了解更多关于上述内容以及使用 awk 解析 CSV 的一般信息。
【讨论】:
【参考方案4】:awk 'BEGIN RS=ORS="\"" NR%2 gsub(" ",",") print' file
开头,设置双引号作为记录分隔符。
对于奇数记录,即外部引号,用逗号替换全局任何空格。
打印每条记录。
【讨论】:
【参考方案5】:这可能对你有用(GNU sed):
sed -E ':a;s/^((("[^"]*")*[^" ]*)*) /\1,/;ta' file
将零个或多个双引号字符串后跟零个或多个非空格字符零个或多个时间后跟一个空格替换为该组后跟一个逗号,重复直到失败。
【讨论】:
以上是关于识别和替换给定文本文件中的选择性空间的主要内容,如果未能解决你的问题,请参考以下文章