简体   繁体   English

Bash-用空格代替下划线,前导/后跟除外

[英]Bash - replacing underscores with spaces, except leading/trailing ones

I want underscores between words to be replaced with spaces, and leading and trailing underscores left alone. 我希望将单词之间的下划线替换为空格,并单独保留前导和尾随下划线。 For example: 例如:

__hello_world_a_b___
hello___world

should become 应该成为

__hello world a b___
hello   world

Using Bash with its regular expression support: 使用Bash及其正则表达式支持:

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

To check that it works, let's make a script that will take the string as argument: 为了检查它是否有效,让我们创建一个脚本,该脚本将字符串作为参数:

#!/bin/bash

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

Call this script banana , chmod +x banana and let's go: 将此脚本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

You could simply use the below Perl command which uses the PCRE verb (*SKIP)(*F) . 您可以简单地使用下面的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___

The above regex would match all the _ except the leading and trailing ones. 上面的正则表达式将匹配所有_除了前导和尾随的。

Another Pure Bash possibility that doesn't use regular expression but extended globs, in a very pedestrian way: 另一个不使用正则表达式而是扩展glob的Pure Bash可能性,以一种非常行人的方式:

#!/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// /_}"

The variables wo_leading will contain the string without leading underscores, and the variable wo_underscore will contain the string without leading and trailing underscores. 变量wo_leading将包含不带下划线的字符串,变量wo_underscore将包含不带下划线和结尾的字符串。 From here, it's easy to get the number of leading and trailing underscore, to replace underscores by spaces in wo_underscore and put back everything together. 从这里,很容易获得前导和尾随下划线的数目,用wo_underscore的空格替换下划线并将所有内容放回去。

Another Perl answer: Perl的另一个答案:

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

That is: a sequence of underscores preceded by a character that is a word character except underscore, and followed by a character that is a word character except underscore. 即:一个下划线序列,其后是一个字符,该字符是除下划线之外的单词字符,然后是一个字符,该字符是除下划线之外的单词字符。

如果您有GNU awk,则可以使用

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM