Target content
I stumbled upon and downloaded an interesting python tutorial on youtube and it brings on its annotations something like:
1. Variables (2:47)
2. Functions (8:50)
3. Calendar (14:10)
4. If Else Statements (37:17)
I have created a README.md file with this annotations, but what happens is that the youtube video link itself uses a sort of sum-up of the time in seconds, which means that 2 minutes and 47 seconds are in reality 167 seconds and I needed to convert it to create links to its parts.
Using vim skills let's see how to convert the time properly.
Introducing our vim friend submatch()
When using Regular expressions we can use groups like this
/\v^(word) (another)
The above search matches "word another" using "very magic" option and also create two regex groups. Now we can reuse the last search like this to exchange words position:
:%s//\2 \1
\2
matches the second group and \1
matches the first one. Now we can use our friend submatch()
, which uses these groups to perform actions like mathematics.
The only problem is that we already have parenthesis in our file, we just need to protect them this way:
/\v\((pattern)\)
The \(
in very magick means a real parenthesis and a non scaped one (
means start of a regex group.
Actually, if you don't use very magic search you kind of have to invert the use of parentheses. With very magic regex groups are not protected and normal parentheses are if we do not use very magic the logic is the oposite.
The substitution command
The below substitution only substitues minutes+seconds to seconds, it does not creates markdown links as I wanted
:'<,'>s/\v\((\d+):(\d+)\)$/\=submatch(1)*60 + submatch(2)
We used a selection to group the lines that have only "minutes + seconds", that's why '<,'>
.
\v ............... very magic enabled
\( ............... literal parenthesis
( ................ start of the first regex group
\d+ .............. at least one digit
: ................ literal colon
\) ............... closing literal parenthesis
$ ................ end of line
\= ............... expression register
submatch(1) ...... the first regex group
Building the final link (markdown)
The video link is https://www.youtube.com/watch?v=4F2m91eKmts and I have saved it on the a
register plus &ts=
to indicate the video part in seconds:
:let @a='https://www.youtube.com/watch?v=4F2m91eKmts&ts='
the search pattern
/\v\. ([^(]*)\((\d+):(\d+)\)
\v ....................... very magic search
\. ....................... literal dot
([^(]*) .................. a regex group that matches everything but opening parenthesis
\( ....................... a literal parenthesis
(\d+) ..................... a digit or more as a regex group
: ......................... literal colon
To be able to creat a markdown link we have to group our submatch()
so then we can combine submatches with the strings
we are going to use in our links. The markdown links are like: [link name](url)
.
:'<,'>s//\=(' ['. submatch(1) . '('. (submatch(2)*60 + submatch(3)). ']')
:'<,'>s//\=(' ['. submatch(1) . '('. (submatch(2)*60 + submatch(3)). ')](' . @a . ')')
'<,'> ................... selected area
// ...................... uses last search
\=( ..................... here we open our big grouping pattern
The part were we combine minutes plus seconds is between parenthesis
How old they are
Let's say you have these lines:
Stallman Richard GNU 1953 USA
Wall Larry Perl 1954 USA
Moolenar Bram Vim 1961 Netherlands
Tridgell Andrew Samba 1967 Australia
Matsumoto Yukihiro Ruby 1965 Japan
Ritchie Dennis C 1941 USA
Thompson Ken Unix 1943 USA
And you want to know how old each one of these guys is right now
:%s,\d\+,\=strftime("%Y")-submatch(0)
:'<,'>s/\v(\d+)/\=("Age: ".(strftime("%Y")-submatch(1)))/
In the second example we had to group all into parentesis \=()
so then we can conatenate the string with the number
Notice: If you want to combine "strings" with numbers you can group the math parth and use "." to concatenate them.
Just increasing and decreasing numbers
Let's say you have these lines:
On this line I have 1 and nothing more
On this line I have 1 and nothing more
On this line I have 1 and nothing more
On this line I have 1 and nothing more
On this line I have 1 and nothing more
On this line I have 1 and nothing more
And you want change them to this:
On this line I have 1 and nothing more
On this line I have 2 and nothing more
On this line I have 3 and nothing more
On this line I have 4 and nothing more
On this line I have 5 and nothing more
On this line I have 6 and nothing more
The simple solution is:
Jump to the first 1 on on the second line:
jf1
Start visual block selection with Ctrl-v and go down 4 lines
with:
4j
Now just press:
g Ctrl-a
Top comments (2)
Great tips overall! Very nice article. It has most of my favorite math tricks in Vim.
One important caveat to watch for is that Vim will interpret numbers like 047 as octal (so that's actually 39 rather than 47.) In your particular examples, that wouldn't matter, because you only have two digit seconds there, and 01 through 07 will behave the same whether octal or decimal, and Vim will interpret 08 and 09 as decimal. So it all looks good... But when you start having three-digit numbers with leading zeroes, that's something to watch for...
I love the g Ctrl-A trick in block visual mode! (Or, more accurately, I just love block visual mode! So cool!)
Thanks for the article again. Looking forward to reading more Vim articles from you.
Hi, Filipe!
I have found a great article I backed up some time ago about "how amazing vim regexes are" and I think you will like reading it:
bitbucket.org/snippets/sergio/7nzqxx
I suggest increasing the font size for better reading.