【问题标题】:insert double quotes for each field enhancement为每个字段增强插入双引号
【发布时间】:2019-08-26 13:01:56
【问题描述】:

我正在根据下面提供的示例寻找以下输入

示例

eno~ename~address~zip
123~abc~~560000~"a~b~c"
245~"abc ~ def"~hyd~560102
333~"ghi~jkl"~pub~560103
444~ramdev "abc def"~ram~10000

预期输出

"eno"~"ename"~"address"~"zip"
"123"~"abc"~""~"560000"~"a~b~c"
"245"~"abc ~ def"~"hyd"~"560102"
"333"~"ghi~jkl"~"pub"~"560103"
"444"~"ramdev ""abc def"""~"ram"~"10000"

当前代码:

awk 'BEGIN{s1="\"";FS=OFS="~"} {for(i=1;i<=NF;i++){if($i!~/^\"|\"$/){$i=s1 $i s1}}} 1' sample

当前代码不适用于最后一行。这是对 insert quotes for each field using awk 的增强

【问题讨论】:

  • 你的问题不是很清楚,但是如果我理解正确的话,你想要的是每个字段周围的引号,字段中间的现有引号加倍,对吗?跨度>
  • 您的最后一行不太有意义。引用“ramdev”的依据是什么?如果我认为单个空格也是波浪号(~)之类的分隔符,即使那样,为什么"abc def" 还要加引号?
  • 查看我之前的评论 - stackoverflow.com/questions/57655449/…。如果您无法在whats-the-most-robust-way-to-efficiently-parse-csv-using-awk 上发布解决方案来为您工作,那么请以该脚本为起点提出问题,而不是其他一些无法工作且无法增强以在您的问题中工作的脚本.
  • 您要做的是使用 Text::CSV Perl 模块的简单任务。 metacpan.org/pod/Text::CSV
  • 在您上一个问题中,在您得到一些答案后,您修改了输入以包含一个字段包含换行符的情况,因此您已经收到的答案无效。如果您确实需要提出新问题,请确保您的示例输入/输出包含带有换行符的字段(以及任何其他重要的情况),如果它们可以出现在您的真实数据中。

标签: perl awk sed


【解决方案1】:

这可能对你有用(GNU sed):

cat <<\! | sed -Ef - file
:a;s/^([^"~][^~]*~+("[^~"]*"~+[^"~][^~]*~+)*[^"]*"[^"~]*)~/\1\n/;ta; #1
s/.*/~&/                                                             #2
s/~"([^"]*)"/~\1/g                                                   #3
s/"/""/g                                                             #4
s/.//                                                                #5
s/[^~]*/"&"/g                                                        #6
y/\n/~/;                                                             #7
!

这个 sed 脚本的工作原理如下:

  1. ~ 在字符串中可能会与字段分隔符混淆。它们需要替换为当前行中不存在的唯一字符。由于 sed 使用换行符来分隔其输入,因此换行符不能出现在模式空间中,因此是此类字符的完美选择。字段由三种类型的字符串组成:

    a) 不以双引号开头和结尾且没有引号的字符串。

    b) 双引号字符串

    c) 不是以双引号开头和结尾的字符串,而是在其中包含引号的字符串。

    后面的字符串需要其中的任何~ 来替换\n。这可以通过循环当前行来实现,留下不包含 ~ 的类型为 a、b 或 c 的字段,并且只替换后面字符串中的 ~

  2. 为了方便下一步,我们为第一个字符串引入了字段分隔符。

  3. 删除所有包含字段的双引号(参见 1b)。

  4. 所有剩余的双引号都在类型 1c 的字符串中,并且可以通过前缀 " 来引用。

  5. 现在删除第 2 步中引入的初始字段分隔符。

  6. 用双引号将所有字段括起来。

  7. 将步骤 1 中引入的换行符替换为其原始值,即 ~

注意GNU sed 似乎有一个错误,即如果翻译命令 (y/../../) 是脚本中的最后一个命令或单行命令,则需要以 ; 为后缀。

上面的解决方法可以输入一行:

sed -E ':a;s/^([^"~][^~]*~+("[^~"]*"~+[^"~][^~]*~+)*[^"]*"[^"~]*)~/\1\n/;ta;s/.*/~&/;s/~"([^"]*)"/~\1/g;s/"/""/g;s/.//;s/[^~]*/"&"/g;y/\n/~/;' file

【讨论】:

  • 我无法使用上述命令执行它。我收到语法错误是否有任何在线 sed 编辑器您尝试过
  • 它说 cat --invalid option --f
  • @user1485267 上面的示例使用 bash shell 并将 here-document 的输出通过管道传输到 sed 命令,该命令通过 -f - 选项将 sed 命令作为来自标准输入的文件接受。另一种方法是将 sed 命令放在一个文件中,例如sedFile,然后使用以下命令调用它们:sed -Ef sedFile file。使sedFile 复制以:a 开头的行到以y/\n/ /; 开头的行。 HTH
  • 如果我将它保存在文件中并按照您的建议运行命令,它会按预期工作。如果我想在单个命令中运行而不是将命令保存在文件中,您可以通过上述命令提供帮助吗?
  • 在上面的命令中,在哪里传递输入文件并存储在不同的输出文件中。我在 cat 之后和结尾都试过了! sample.txt 它不起作用
猜你喜欢
  • 2019-12-30
  • 2017-09-08
  • 1970-01-01
  • 1970-01-01
  • 2014-09-18
  • 2011-11-30
  • 1970-01-01
  • 2018-07-16
  • 1970-01-01
相关资源
最近更新 更多