2016-04-27 117 views
0

我想用_替換JSON文件的密鑰名稱中的連字符-,而不會影響鍵值對的值端。如何使用sed替換模式之間的字符

例輸入:

{ 
    "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 
} 
+0

對於所示的輸入,一個簡單的'用​​sed的/ -/_ /''會的工作 - 也許添加一些情況下,如連字符僅在價值,鑰匙等多個連字符? –

回答

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命令(分行標籤,如果模式空間被改變)。

對於BSD的sed如在Mac OS中發現,標籤必須在一個單獨的命令:

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

注意,所有這一切的固有的限制是,必須不存在引號之間的任何冒號通常建議使用合適的JSON解析器(例如jq)來執行此類操作。

+0

感謝Benjamin,即使在嵌套的json結構中,條件分支也能工作。 – Niels

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 
0

只需使用AWK:

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