如何使用sed替换模式之间的字符

时间:2016-04-27 15:07:00

标签: sed

我正在尝试使用-替换JSON文件的密钥名称中的连字符_,而不会影响键值对的值侧。

示例输入:

{
  "outcome": "failed", 
  "failure-description": "ra ra ra - and more", 
  "rolled-back": true
}

有没有办法用sed做到这一点?它可能是匹配模式,其中sed只会在"(.*[^"])":之间替换,但我无法找到如何替换匹配子字符串中不需要的字符。

预期结果如下:

{
  "outcome": "failed", 
  "failure_description": "ra ra ra - and more", 
  "rolled_back": true
}

3 个答案:

答案 0 :(得分:0)

这样可行:

$ sed 's/-\([^:]*\):/_\1:/' infile 
{
  "outcome": "failed", 
  "failure_description": "ra ra ra - and more", 
  "rolled_back": true
}

这会查找-后跟捕获的除冒号之外的一系列字符,然后是冒号;它用下划线替换连字符,并将捕获的组和冒号放回去。

这个限制是它只替换第一个连字符。假设我们的输入如下:

{
  "outcome": "failed", 
  "failure-description": "ra ra ra - and more", 
  "two-hyphens-here": "ra ra ra - and more", 
  "rolled-back": true
}

要在冒号之前替换所有连字符,我们可以使用条件分支:

$ sed ':a;s/-\([^:]*\):/_\1:/;ta' infile
{
  "outcome": "failed", 
  "failure_description": "ra ra ra - and more", 
  "two_hyphens_here": "ra ra ra - and more", 
  "rolled_back": true
}

设置标签(:a)并使用t命令(如果模式空间已更改,则分支标记)。

对于在Mac OS中找到的BSD sed,标签必须在单独的命令中:

sed -e ':a' -e 's/-\([^:]*\):/_\1:/;ta' infile

请注意,所有这些的固有限制是引号之间不能有任何冒号,并且通常建议使用适当的JSON解析器(如jq)来执行此类操作。

答案 1 :(得分:0)

使用扩展的正则表达式和括号结构。

-r, --regexp-extended
  use extended regular expressions in the script.

这会产生正确的结果,但可能需要进行一些调整以强化正则表达式以防止错误匹配:

sed -re 's/([:alpha:]*)[-]([:alpha:]*)/\1_\2/'

结果:

{
  "outcome": "failed",
  "failure_description": "ra ra ra - and more",
  "rolled_back": true
}

注意,如果值侧包含模式,则上面给出的简单表达式是不合适的。检查您的数据集,根据需要添加更多带括号的表达式和对它们的引用,以更紧密地锚定匹配。可以嵌套带括号的表达式,但这确实会使确定对它的后向引用变得复杂。

$ sed --version
GNU sed version 4.1.5

答案 2 :(得分:0)

只需使用awk:

$ awk 'BEGIN{FS=OFS="\": \""} {gsub(/-/,"_",$1)} 1' file
{
  "outcome": "failed",
  "failure_description": "ra ra ra - and more",
  "rolled_back": true
}