Reputation: 8074
I have something like a printf string, e.g. The %1 fox jumped over the %2 bridge
.
And I want to transform it into The {0} fox jumped over the {1} bridge
.
That is: get string, search for %(\d+)
pattern, turn it into {$1 - 1}
, repeat until the end of the string.
Is there an easy way to do that in linux (an awk one-liner for example)? I have read that sed shouldn't be an option here.
IMPORTANT: ah, unfortunately, I can't use perl solutions!
NOTES: although I think I won't find tricky stuff in my strings like %%
or %%1
, I was trying to implement a solution dealing with that. A test string I was using is %1 aaa %%2 bbb%%% ccc%3.,45--- ddd%6%7
. For this test string, I would expect the output {0} aaa %{1} bbb%%% ccc{2}.,45--- ddd{5}{6}
Upvotes: 0
Views: 143
Reputation: 8174
Another solution using sed
sed -r '
# replace all leading 0s by _
:d; s/%([0-9]+)0(\b|_)/%\1_\2/g; td;
# decrement last digit only
s/%([0-9]*)1(\b|_)/%\10\2/g;
s/%([0-9]*)2(\b|_)/%\11\2/g;
s/%([0-9]*)3(\b|_)/%\12\2/g;
s/%([0-9]*)4(\b|_)/%\13\2/g;
s/%([0-9]*)5(\b|_)/%\14\2/g;
s/%([0-9]*)6(\b|_)/%\15\2/g;
s/%([0-9]*)7(\b|_)/%\16\2/g;
s/%([0-9]*)8(\b|_)/%\17\2/g;
s/%([0-9]*)9(\b|_)/%\18\2/g;
#remove zero to left
s/%0(_+)/%\1/g;
#replace _ by 9s
:a; s/%([0-9]+)_(\b|_)/%\19\2/g; ta;
s/%([0-9]+)/{\1}/g;'
you get
he {0} fox jumped over the {1} bridge.
and
{0} aaa %{1} bbb%%% ccc{2}.,45--- ddd{5}{6}
Upvotes: 2
Reputation: 11246
Another awk way
awk '{while(sub(/%[0-9]+/,"{"x++"}"));}!(x=0)' file
Just loops through the line incrementing x
every match of %[number]
and subbing. Sets x back to 0 at the end of line
For the new test string you can use
awk '{while(match($0,/%([0-9]+)/,a))sub(a[0],"{"a[1]-1"}")}1' file
Although this requires GNU awk for the third argument to match.
Example
%1 aaa %%2 bbb%%% ccc%3.,45--- ddd%6%7
becomes
{0} aaa %{1} bbb%%% ccc{2}.,45--- ddd{5}{6}
Upvotes: 4
Reputation: 290525
tAssuming no other %
appear and they are sequential:
awk -F"%" -v OFS="{" '{for (i=1;i<=NF;i++) sub(i-1,i-2"}",$i)}1' file
This plays with the field separator setting it to %
. This way, the field are split like this:
The %1 fox jumped over the %2 bridge
^^^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^
$1 $2 $3
and then it is a matter of replacing the number i
with i-1
whenever reading the field i+1
. Finally, we glue it together by setting the output field separator to {
.
$ cat a
The %1 fox jumped over the %2 bridge
The %1 fox jumped over the %2 bridge and %3 other %4 things
$ awk -F"%" -v OFS="{" '{for (i=1;i<=NF;i++) sub(i-1,i-2"}",$i)}1' a
The {0} fox jumped over the {1} bridge
The {0} fox jumped over the {1} bridge and {2} other {3} things
Note I am using sub()
because it replaces just once. This way, we make sure other occurrences of 1
won't be changed when modifying the field $1
, etc.
From the link above:
sub(regexp, replacement, target)
The sub function alters the value of target. It searches this value, which should be a string, for the leftmost substring matched by the regular expression, regexp, extending this match as far as possible. Then the entire string is changed by replacing the matched text with replacement. The modified string becomes the new value of target.
Upvotes: 2