我想用字符串中的另一个字符替换字符,但仅当字符出现在字符串的分隔子字符串中时。例如,对于字符串:
B [B] ABC [ABC] BBB [BBB]
我想将“b”更改为“x”,但前提是它在方括号内“[...]”。因此,所需的结果是字符串:
B [X] ABC [AXC] BBB [XXX]
我的偏好是sed或bash解决方案因为它们在我的舒适区域,但任何适用于Mac OS X的解决方案都没问题。从搜索来看,似乎这可以通过使用负向前瞻和负面后瞻的sed来完成,但我不相信这些功能在Mac版本的sed上可用。
答案 0 :(得分:2)
使用GNU sed:
$ sed -r ':a;s/(\[[^]]*)b/\1x/;ta' <<< "b[b]abc[abc]bbb[bbb]"
b[x]abc[axc]bbb[xxx]
:a
为即将推出的循环添加标签s
:替换命令(\[[^]]*)
:搜索并捕获[
后跟任何非]
字符b
x
ta
:如果之前的替换成功,则循环标记:a
(替换b
的任何其他匹配项)对于OS X上的GNU sed:
brew uninstall gnu-sed
答案 1 :(得分:1)
这是一种(相当强力)纯粹的Bash解决方案:
raw='b[b]abc[abc]bbb[bbb]'
cooked=
declare -r delimited_rx='^(.*)\[([^][]*)\](.*)$'
while [[ $raw =~ $delimited_rx ]] ; do
raw=${BASH_REMATCH[1]}
printf -v cooked '[%s]%s%s' \
"${BASH_REMATCH[2]//b/x}" \
"${BASH_REMATCH[3]}" \
"$cooked"
done
cooked=$raw$cooked
printf '%s\n' "$cooked"
答案 2 :(得分:1)
因为&#34;任何适用于Mac OS X的解决方案都很好&#34;,请考虑Perl:
perl -ple 's{\[([^][]*)\]}{ ($m=$1)=~s/b/x/g; "[$m]" }eg' <<< 'b[b]abc[abc]bbb[bbb]'
答案 3 :(得分:0)
使用gnu-awk:
s='b[b]abc[abc]bbb[bbb]'
awk -v OFS= -v FPAT='\\[[^]]+\\]|[^[]*' '{
for (i=1; i<=NF; i++) if ($i ~ /\[.*\]/) gsub(/b/, "x", $i)} 1' <<< "$s"
<强>输出:强>
b[x]abc[axc]bbb[xxx]
在OSX上我使用home brew
安装了gnu-awk。
答案 4 :(得分:0)
$ awk '{ while(match($0,/\[[^][]*b[^][]*\]/)) { tgt=substr($0,RSTART,RLENGTH); gsub(/b/,"x",tgt); $0=substr($0,1,RSTART-1) tgt substr($0,RSTART+RLENGTH) } } 1' file
b[x]abc[axc]bbb[xxx]
答案 5 :(得分:0)
感谢您提供的精彩解决方案!所有解决方案(sed,awk和bash)都完美地在我的系统上运行。由于我对sed有点偏爱,我发现使用t命令和循环的sed解决方案非常好。需要稍加修改,即更换;使用换行符,并将-r选项替换为-E,以使其在我的OS X系统上运行:
var noteStr = "1-415-655-0001 US TOLL\n\nAccess code: 197 703 792"
/* since we're using native pattern matching, let's use a native method
also when extracting the first row (even if this is somewhat simpler
if using Foundation bridged NSString methods) */
if let firstRowChars = noteStr.characters.split("\n").first,
case let firstRow = String(firstRowChars) {
// pattern matching for number characters
let pattern = UnicodeScalar("0")..."9"
let numbers = firstRow.unicodeScalars
.filter { pattern ~= $0 }
.reduce("") { String($0) + String($1) }
print(numbers) // 14156550001
/* Alternatively use .reduce with an inline if clause directly:
let numbers = firstRow.unicodeScalars
.reduce("") { pattern ~= $1 ? String($0) + String($1) : String($0)} */
}
我做了另一个修改,以确保只有当一个右方括号伴随一个开口方括号时才进行替换:
sed -E '
:a
s/(\[[^]]*)b/\1x/
ta
' <<< "b[b]abc[abc]bbb[bbb]"
b[x]abc[axc]bbb[xxx]
答案 6 :(得分:0)
echo 'b[b]abc[abc]bbb[bbb]' | awk -vRS='[][]' 'NR%2==0{gsub("b","x")}{printf $0 RT}'
b[x]abc[axc]bbb[xxx]