2014-11-01 62 views
1

我想要用空格替換單詞之間的下劃線,單獨留下前導和尾部下劃線。例如:Bash - 用空格替換下劃線,除了前導/後綴

__hello_world_a_b___ 
hello___world 

應該成爲

__hello world a b___ 
hello world 
+0

-1做它 「與陣列和功能」。如果這是一個合法的要求,你應該解釋它;如果沒有,你應該刪除它(並且只是要求最好的方法)。 – ruakh 2014-11-02 01:30:34

回答

1

使用bash其正則表達式的支持:

string='__hello_world_a_b___' 
[[ $string =~ ^(_*)(.*[^_])(_*)$ ]] 
echo "${BASH_REMATCH[1]}${BASH_REMATCH[2]//_/ }${BASH_REMATCH[3]}" 

要檢查它的工作原理,讓我們做一個腳本,將採取字符串作爲參數:

#!/bin/bash 

string=$1 
[[ $string =~ ^(_*)(.*[^_])(_*)$ ]] 
echo "${BASH_REMATCH[1]}${BASH_REMATCH[2]//_/ }${BASH_REMATCH[3]}" 

調用此腳本bananachmod +x banana,讓我們去:

$ ./banana '__hello_world_a_b___' 
__hello world a b___ 
$ ./banana '__hello_world_a_b' 
__hello world a b 
$ ./banana 'hello_world_a_b___' 
hello world a b___ 
$ ./banana 'hello_world_a_b' 
hello world a b 
$ ./banana '___' 

$ # the previous output is empty 
$ ./banana $'___hello_world_with\na_newline___' 
___hello world with 
a newline___ 
$ ./banana 'hello___world' 
hello world 
0

你可以簡單地使用下面的Perl命令,該命令使用PCRE動詞(*SKIP)(*F)

$ echo "hello___world" | perl -pe 's/(?:^_+|_+$)(*SKIP)(*F)|_/ /g' 
hello world 
$ echo "__hello_world_a_b___" | perl -pe 's/(?:^_+|_+$)(*SKIP)(*F)|_/ /g' 
__hello world a b___ 

上述正則表達式可以匹配所有的_,除了前導和尾隨之外。

+0

PCRE動詞都有點微妙,並沒有很廣泛的理解。所以,這是主觀的,但是我認爲最好寫一些類似'perl -pe'的if(m/^(_ *)([^ _]。* [^ _ \ n])(_ * \ n?) \ z /){my($ leading,$ words,$ trailing)=($ 1,$ 2,$ 3); $ words =〜s/_// g; $ _ =「$ leading $ words $ trailing」}「'。 – ruakh 2014-11-02 01:44:55

+0

@ruakh它已經被eckes建議。但他刪除了他的答案。如果你理解上面的PCRE動詞,你不需要像上面那樣寫一個長的代碼。 – 2014-11-02 01:51:17

0

不使用正則表達式,但延長的水珠,在一個非常行人路的另一種純擊可能性:

#!/bin/bash 

shopt -s extglob 

string=$1 

wo_leading=${string##+(_)} 
wo_underscore=${wo_leading%%+(_)} 

printf -v leading '%*s' "$((${#string}-${#wo_leading}))" 
printf -v trailing '%*s' "$((${#wo_leading}-${#wo_underscore}))" 

echo "${leading// /_}${wo_underscore//_/ }${trailing// /_}" 

變量wo_leading將包含字符串沒有前導下劃線,並且變量wo_underscore將包含沒有開頭和尾部下劃線的字符串。從這裏可以很容易地得到前後的下劃線數字,用wo_underscore中的空格替換下劃線,並將所有內容放在一起。

0

另一個Perl的答案:

perl -pe 's/(?<=[^\W_])(_+)(?=[^\W_])/ " " x length($1) /ge' <<END 
__hello_world_a_b___ 
hello___world 
END 
__hello world a b___ 
hello world 

即:由一個字符,除了下劃線單詞字符之前,並且通過字符後跟下劃線的序列是一個字字符除了下劃線。

0

如果你有GNU AWK,你可以用

awk '{match($0,"^(_*)(.*[^_])(_*)$",arr); print arr[1] gensub("_"," ","g",arr[2]) arr[3]}'