Article 5Q21Y Double a number with sed

Double a number with sed

by
shruggy
from LinuxQuestions.org on (#5Q21Y)
First, some context.

There is an old, but very good vi/ex tutorial series by Walter Alan Zintz. Recently, I stumbled upon a modernized version of it, adapted for Vim usage by Barry Arthur and Israel Chauca: https://dahu.github.io/vim_waz_ere

It's still incomplete, but already useful. Among other topics, they expanded the chapter on the substitute command and even provided some Vim-specific exercises not found in the original series.

One of those exercises deals with the following dataset:
Code:@items = [
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15]
]There are two questions:

1. What command would remove the 3rd column of numbers?
Unlike sed, ed, edbrowse, vile and elvis, the substitute command in Vim doesn't have the number flag that allows you to specify the Nth match.

So an obvious sed/ed solution s/\s*\w*,//3 won't work in Vim. What they suggest instead is setting the start of the match, an equivalent to lookbehind:
Code:s/\v/(.{-},){2}\zs.{-},//A rather inelegant solution compared to sed/ed.
There's a bonus question, too:

2. What command would double the numbers in the third column instead of removing them?
As a solution they suggest using substitute with an expression, a powerful, but somewhat esoteric Vim feature:
Code:s/\v%(\d+,\s*){2}\zs\d+/\=submatch(0)*2
That got me thinking whether a transformation like this was possible with sed, and what it would look like. Awk is certainly better suited for this kind of task, but that's beyond the point.

My first idea was to use substitute with the e flag, like this:
Code:sed -E '
/^\s*\[/{
h
s/^([^,]+,){2}([^,]+).*/expr \2 + \2/e
G
s/^(.+)\n(([^,]+,){2}\s*)[^,]+/\2\1/
}'This is probably as practical as it goes with sed.

Of course, there is plenty of information at http://sed.sf.net on the subject of doing arithmetic in sed proper, but it's anything other than practical. Nevertheless, after some thought (and using that site as reference) I came up with this:
Code:#!/bin/sed -Ef
# Double a natural number
# Carry is indicated by upper case
y/0123456789/abcdeFGHIJ/
s/^[F-J]/A&/
s/[a-e][F-J]/\u&/g
s/[F-J]([a-eA-E]|$)/\l&/g
y/abcdefghijABCDEFGHIJ/02468024681357913579/For an example like above, where all numbers are less than 50, this will do as well:
Code:#!/bin/sed -Ef
# Quick'n'dirty doubling of a number
# Only numbers up to 49 are allowed
/^[0-4]?[0-9]$/!{
i\
Number out of range. Acceptable are numbers 0 - 49.\
Invalid input occured at this line:
=
q
}

s/[5-9]/0&/
y/123456789/246802468/
s/.?0.$/&0123456789/
s/(.).?(.).*\1(.).*/\3\2/What do you think?latest?d=yIl2AUoC8zA latest?i=sdXjuFodKWs:SW962jkH8FU:F7zBnMy latest?i=sdXjuFodKWs:SW962jkH8FU:V_sGLiP latest?d=qj6IDK7rITs latest?i=sdXjuFodKWs:SW962jkH8FU:gIN9vFwsdXjuFodKWs
External Content
Source RSS or Atom Feed
Feed Location https://feeds.feedburner.com/linuxquestions/latest
Feed Title LinuxQuestions.org
Feed Link https://www.linuxquestions.org/questions/
Reply 0 comments