我有這個測試文件。使用sed替換文本只是在引號中
[[email protected] ~]# cat f.txt "a aa" MM "bbb b" MM MM MM"b b " [[email protected] ~]#
我想用引號替換引號中的所有空格字符,只是在引號中。所有不包括引號的字符都不應該被觸及。也就是說,我要的是類似於:
"a_aa" MM "bbb__b" MM MM MM"b_b_"
可以這樣使用的sed實施?
謝謝,
我有這個測試文件。使用sed替換文本只是在引號中
[[email protected] ~]# cat f.txt "a aa" MM "bbb b" MM MM MM"b b " [[email protected] ~]#
我想用引號替換引號中的所有空格字符,只是在引號中。所有不包括引號的字符都不應該被觸及。也就是說,我要的是類似於:
"a_aa" MM "bbb__b" MM MM MM"b_b_"
可以這樣使用的sed實施?
謝謝,
這是一個完全不重要的問題。
這適用於下劃線代替,引號裏的第一空間:
$ sed 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' f.txt
"a_aa" MM "bbb_ b"
MM MM
MM"b_b "
$
在這個例子中,在裏面有任何的報價不超過兩個空間,人們很容易簡單地重複命令,但它給出了一個不正確的結果:
$ sed -e 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' \
> -e 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' f.txt
"a_aa"_ MM "bbb_ b"
MM MM
MM"b_b_"
$
如果你的的sed
版本支持「擴展正則表達式」,那麼這個工程的樣本數據:
$ sed -E \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> f.txt
"a_aa" MM "bbb__b"
MM MM
MM"b_b_"
$
對於雙引號內的每個空格,你必須重複那個可怕的正則表達式 - 因此對於第一行數據來說是三次。
正則表達式可以如解釋:
因爲起步錨的,這必須每空重複一次......但sed
具有循環結構,所以我們可以做到這一點:
$ sed -E -e ':redo
> s/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/
> t redo' f.txt
"a_aa" MM "bbb__b"
MM MM
MM"b_b_"
$
的:redo
定義了一個標籤; s///
命令與以前一樣;如果自從上一次讀取一行或跳轉到標籤以來進行了任何替換,則t redo
命令將跳轉到標籤。
鑑於該意見的討論中,有幾個值得一提的幾點:
的-E
選項適用於sed
在MacOS X(10.7.2測試)。GNU版本sed
的相應選項是-r
(或--regex-extended
)。 -E
選項與grep -E
(它也使用擴展正則表達式)一致。 「經典Unix系統」不支持sed
(Solaris 10,AIX 6,HP-UX 11)的ERE。
可以代替我用了?
(這是強制使用的ERE,而不是BRE的唯一字符)與*
,然後用括號(需要反斜槓在一個BRE他們面前處理使他們成爲捕獲括號),使腳本:
sed -e ':redo
s/^\(\([^"]*\("[^ "]*"\)*\)*\)\("[^ "]*\) \([^"]*"\)/\1\4_\5/g
t redo' f.txt
這將產生相同的輸入相同的輸出 - 我試着輸入一些稍微複雜的圖案:
"a aa" MM "bbb b"
MM MM
MM"b b "
"c c""d d""e e" X " f "" g "
"C C" "D D" "E E" x " F " " G "
氏s給出的輸出:
"a_aa" MM "bbb__b"
MM MM
MM"b_b_"
"c_c""d_d""e__e" X "_f_""_g_"
"C_C" "D_D" "E__E" x "_F_" "_G_"
即使BRE符號,sed
支持\{0,1\}
表示法指定0或1次出現先前RE術語,所以?
版本可以使用被轉換爲BRE:
sed -e ':redo
s/^\(\([^"]*\("[^ "]*"\)\{0,1\}\)*\)\("[^ "]*\) \([^"]*"\)/\1\4_\5/g
t redo' f.txt
這產生與其他選擇相同的輸出。
謝謝你。優秀的解決方但是擴展的正則表達式開關在我的系統上是*** - r ***。 –
@JonathanLeffler優秀的正則表達式使用,特別是'(「[^」] *「)?'碰撞替代,但爲什麼'?'而不是'*'? – potong
我認爲你可以使用'?'或'* ''成功了('*'處理樣本數據)。我使用'?'是因爲它可能有助於限制正則表達式的回溯數量,這非常複雜(這不是我想要的正則表達式必須急於破譯!)。 –
一個莫名其妙不尋常的答案XSLT 2.0:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"></xsl:output>
<xsl:template name="init">
<xsl:for-each select="tokenize(unparsed-text('f.txt'),' ')">
<xsl:for-each select="tokenize(.,'"')">
<xsl:value-of select="if (position() mod 2 = 0)
then concat('"',translate(.,' ','_'),'"') else ."></xsl:value-of>
</xsl:for-each>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
爲了測試是否,只得到sourceforge上saxon.jar並使用以下命令行:
java -jar saxon9.jar -it:init regexp.xsl
XSLT文件包含對f.txt的引用,則文本文件必須與xslt文件位於同一目錄中。通過給樣式表一個參數可以很容易地改變它。
它在一次通過。
如果引用的文本全部在不同的行上,這將非常簡單。所以一種方法是分割文本,這樣你就可以做到,做簡單的轉換,然後重建線條。
拆分文本是容易的,但我們需要的是爲
爲了做到這一點,我們可以用符號表示它屬於哪個類的每一行結束。我會用1和2,直接對應上面的。在SED,我們有:
sed -e 's/$/1/' -e 's/"[^"]*"/2\n&2\n/g'
這將產生:
2
"a aa"2
MM 2
"bbb b"2
1
MM MM1
MM2
"b b "2
1
這很容易進行改造,只需使用
sed -e '/".*"/ s/ /_/g'
給
2
"a_aa"2
MM 2
"bbb__b"2
1
MM MM1
MM2
"b_b_"2
1
最後,我們需要把它放回去。這實際上是在SED很可怕,但使用的保留空間是可行的:(這將是更清晰了很多,例如,AWK)
sed -e '/1$/ {s/1$//;H;s/.*//;x;s/\n//g}' -e '/2$/ {s/2$//;H;d}'
管的三個步驟在一起,你就大功告成了。
這可能會爲你工作:
sed 's/^/\n/;:a;s/\(\n[^"]*"[^ "]*\) \([^"]*"\)\n*/\1_\2\n/;ta;s/\n//;ta;s/\n//' file
說明:
前面加上一個\n
到線的起點,這將被用來沿着換人磕碰。在"
之內替換一個與
_
,然後在那裏爲\n
準備好下一輪替換。取代所有後,刪除
\n
並重復。當發生所有替換時,請刪除\n
分隔符。
或該:
sed -r ':a;s/"/\n/;s/"/\n/;:b;s/(\n[^\n ]*) ([^\n]*\n)/\1_\2/g;tb;s/\n/%%%/g;ta;s/%%%/"/g' file
說明:
「與\n
小號的替換第一組""
。用_
替換換行符之間的第一個空格,重複。將\n
替換爲一個唯一的分隔符(%%%
),從頭開始重複。最後用"
代替所有%%%
。
的第三種方式:
sed 's/"[^"]*"/\n&\n/g;$!s/$/@@@/' file |
sed '/"/y/ /_/;1{h;d};H;${x;s/\n//g;s/@@@/\n/g;p};d'
說明:
環繞所有引用的表達式("..."
)與換行符(\n
的)。在除最後一行之外的所有行上插入行尾分隔符@@@
。將結果傳遞給第二個sed
命令。將的全部內容翻譯爲
_
,其中的內容爲"
。將每條線存放在容納空間(HS)中。在文件中,交換到HS的結束,並刪除所有\n
的,並與\n
代替結束行分隔符的
最後:
sed 's/\("[^"]*"\)/$(tr '"' ' '_'"'<<<'"'"'\1'"'"')/g;s/^/echo /' file | sh
或GNU sed的:
sed 's/\("[^"]*"\)/$(tr '"' ' '_'"'<<<'"'"'\1'"'"')/g;s/^/echo /e' file
留給讀者解決。
順便說一句:好問題 - 特別是有很好的示例輸入和所需的輸出。 –