【问题标题】:Find and replace tab to spaces for a particular pattern in a unix file which is tab-delimited as field separator查找并将制表符替换为 unix 文件中特定模式的空格,该文件以制表符分隔作为字段分隔符
【发布时间】:2016-01-09 14:00:04
【问题描述】:

好的。标头可能会令人困惑,但要详细说明,我在 unix 中有一个文件,它已经是一个制表符分隔的文件,我正在尝试在其中进行 bcp。但问题出在其中一些随机值在其中包含制表符的列中。但实际上并非如此随机的。该列中的选项卡仅在双引号值内。这个额外的选项卡可以就在双引号之后,也可以就在双引号内的单词之前和之间。

所以我想将这些标签替换为空格。

例如

HAPPINESS       ALEXIS JORDAN   "HAPPINESS      "       CASH    024     Producer                ABRAMUS QUARTERLY       HAPPINESS       D658    Columbia        D658    Columbia        C283    Columbia Records Group  1Q15
HAPPINESS       ALEXIS JORDAN   "HAPPINESS      ALWAYS" CASH    024     Producer                ABRAMUS QUARTERLY       HAPPINESS       D658    Columbia        D658    Columbia        C283    Columbia Records Group  1Q15
HAPPINESS       DEADMAU5/ALEXIS JORDAN  "       HAPPINESS       "       CASH    024     Producer                ABRAMUS QUARTERLY       HAPPINESS       D658    Columbia        D658    Columbia        C283    Columbia Records Group  1Q15

请找到以上文本供您参考。 请帮忙。提前致谢。

【问题讨论】:

  • 忘记在双引号内的每一行中添加一个制表符。

标签: perl shell unix sed ksh


【解决方案1】:

考虑使用 Perl:

perl -pe 's{"\K(.*?)(?=")}{$1 =~ tr/\t/ /r}eg' filename

这会将正则表达式"\K(.*?)(?=") 匹配的所有内容替换为表达式$1 =~ tr/\t/ /r 的结果。 eg 修饰符是替换 globally 所必需的(如果一行中有多个带引号的字符串)和替换 expressions 评估。

注意事项:

  • \K 之前的所有内容都必须存在才能使某些内容成为匹配,但使其实际上不是匹配的一部分。
  • (?=") 是一个前瞻术语;如果后面跟着",则匹配一个空字符串
  • .*? 非贪婪匹配任何字符串,即采用最短匹配匹配而不是最长匹配

因此,正则表达式匹配" 和下一个" 之间的所有内容,并将其捕获为$1。替换子句中的表达式返回这个捕获的值,用空格替换制表符,它被硬塞到原来的字符串原来的位置。

【讨论】:

  • 我试过上面的代码。我得到了这个 .. perl -pe 's{"\K(.*?)(?=")}{$1 =~ tr/\t/ /r}eg'solided_ppb_20151001.txt21 Bareword 在操作员预期的位置找到 - e 第 1 行,"tr/\t/ /r" 附近 -e 第 1 行,"tr/\t/ /r" 附近的语法错误 由于编译错误,-e 的执行中止。我对perl没有太多想法。请帮忙。 TIA
  • 我做了一些挖掘,发现我的 perl 是旧版本的。所以我删除了 /r 但现在我收到“在 -e 第 1 行, 第 1 行尝试修改只读值”错误。请帮忙。
  • 自 Perl 5.14 起,r 修饰符为 trs 等。如果您的 Perl 较旧,请使用 perl -pe 's{"\K(.*?)(?=")}{$x = $1; $x =~ tr/\t/ /; $x}eg' filename。复制是必要的,因为$1 是只读值,而没有r=~ tr/\t/ / 会尝试修改左侧。
【解决方案2】:

您可以使用此gnu-awk 命令转换引号内的制表符:

awk -v FPAT='"[^"]+"|[^\t]+' '{for (i=1; i<=NF; i++) if ($i ~ /^"/)
       gsub(/\t/, "   ", $i)} 1' OFS='\t' file

FPAT='"[^"]+"|[^\t]+' 用双引号或用制表符分隔字段的输入。

给定样本的cat-vt 的输出:

awk -v FPAT='"[^"]+"|[^\t]+' '{for (i=1; i<=NF; i++) if ($i ~ /^"/) gsub(/\t/, "   ", $i)} 1' OFS='\t' file|cat -vt
HAPPINESS^IALEXIS^IJORDAN^I"HAPPINESS   "^ICASH^I024^IProducer^IABRAMUS^IQUARTERLY^IHAPPINESS^ID658^IColumbia^ID658^IColumbia^IC283^IColumbia^IRecords^IGroup^I1Q15
HAPPINESS^IALEXIS^IJORDAN^I"HAPPINESS   ALWAYS"^ICASH^I024^IProducer^IABRAMUS^IQUARTERLY^IHAPPINESS^ID658^IColumbia^ID658^IColumbia^IC283^IColumbia^IRecords^IGroup^I1Q15
HAPPINESS^IDEADMAU5/ALEXIS^IJORDAN^I"   HAPPINESS   "^ICASH^I024^IProducer^IABRAMUS^IQUARTERLY^IHAPPINESS^ID658^IColumbia^ID658^IColumbia^IC283^IColumbia^IRecords^IGroup^I1Q15

【讨论】:

  • 感谢您的回复。但是上面的命令将替换第一个双引号之前和第二个双引号之后的制表符。我不想要那个.. 我想替换两个双倍配额内的任何制表符,并且只是添加文件已经是制表符分隔的一个。 TIA。阿尤什
  • 不确定你的意思是什么,因为在我的回答中你可以在第一个双引号之前看到该选项卡,即"HAPPINESS 没有被替换。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-19
  • 2017-02-24
  • 2015-07-09
  • 1970-01-01
  • 1970-01-01
  • 2014-05-24
  • 1970-01-01
相关资源
最近更新 更多