2014-11-01 153 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]}'