Stanley Semilla
Stanley Semilla

Reputation: 65

Bash string replace function similar to Javascript String.prototype.replace()

In JS, I can use a function String.prototype.replace() when replacing a submatch in a regular expression. For example:

var x = 'a1b2c3'.replace(/(\d+)/g, (num) => {
    return num*num+1
})
console.log(x)
// 'a2b5c10'

I've tried using sed but it seems that invoking an operator $(()) inside of the replacement is not possible.

$ echo "a1b2c3" | sed 's/\([^0-9]*\)\([0-9]\)\([^0-9]*\)/\1$((\2*\2+1))\3/g'
# Output: a$((1*1+1))b$((2*2+1))c$((3*3+1))

Is there a similar tool or function in bash that has the functionality similar to JS's String.replace()?

Upvotes: 4

Views: 330

Answers (2)

Inian
Inian

Reputation: 85780

The bash shell does support a native regex operator which you can enable with the ~ flag. All you need to do is define a regex, take the captured groups and replace them with the modified values

str='a1b2c3'
re='^.*([0-9]+).*([0-9]+).*([0-9]+).*$'
if [[ $str =~ $re ]]; then
    for match in "${BASH_REMATCH[@]}"; do
        final="${str/$match/$((match*match+1))}"
    done
fi
printf '%s\n' "$final"

The [[ $str =~ $re ]] does the regex match and updates the captured group array ${BASH_REMATCH[@]}. So for each of the element in the order of their appearance, we do the string substitution operator ${str/old/new}. The replacement value in your case is the number multiplied with itself and added by 1.

Add more capturing groups to the regex .*([0-9]+) for subsequent matches.


If not for a pure bash solution above, using an external utility like perl, one could do it as

perl -pe 's/\d+/$&*$&+1/ge' <<<"$str"

The $& refers to the captured digit in the string and the e flag allows do arithmetic operations over the captured groups.

Upvotes: 1

oguz ismail
oguz ismail

Reputation: 50785

You can implement this in gawk using match() and substr().

echo "a1b2c3" | awk '{
    head = ""
    tail = $0

    while (match(tail, /[0-9]+/)) {
        num = substr(tail, RSTART, RLENGTH)
        num = num * num + 1
        head = head substr(tail, 1, RSTART-1) num
        tail = substr(tail, RSTART + RLENGTH)
    }

    print head tail
}'

Output

a2b5c10

Upvotes: 1

Related Questions