loading...

Formating Dates With Vim Substitutuions

voyeg3r profile image Sérgio Luiz Araújo Silva Updated on ・2 min read

The problem

I have stumbled upon an article on how to format dates using vim sub-expression and sub-match tricks in order to format dates, but what happens is that the original article shows examples that work on MacOS and does not have comments section. So I decided to adapt what I have learned reading the article and some personal research.

Let's say you have a HTML file with a large number of lines like this:

<time datetime="2017-10-17">2017-10-17</time>

Our mission is to change the view of the result to the public, keeping our internal html as it is, so the change will be:

<time datetime="2017-10-17">october 17, 2017</time>

The regex to match our date

/>\zs\v\d{4}-\d{2}-\d{2}

>  .................. literal >
\zs ................. start of our match
\v .................. very magic search (avoid backslashes)
\d .................. digits [0-9]
\{4} ................ four times

Using an expression in our substitution

If you have a series of numbers in your file and want to increase them on the substitution you can go:

0 first line
1 second line
2 third line

:%s/\v\d+/\=submatch(0)+1

\v .......... very magic
\d+ ......... a digit or more
\=submatch(0)  the whole search match

Of course, in the above example we could have done:

:g/./exec "normal \<c-a>"

Whic means:

.  ................ every lines that has at least one char '.'
exec .............. execute
normal ............ a normal command
\<c-a> ............ as we used double quotes: the Ctrl-a to increase

But the problem is that in some situations things are a little more complex

You can even use functions as expressions in substitutions. Copy the function bellow to the clipboard:

function! Hello()
    return "Hello World"
endfunction

and run:

:@0

The above command loads de function with no need to save on your vimrc.

Now let's substitute "amazing" with the return of our function:

This is amazing
This is amazing
This is amazing
This is amazing
This is amazing
This is amazing

:%s/amazing/\=Hello()

So for the dates we can do:

%s/>\v\zs\d{4}-\d{2}-\d{2}/\=system('date -d "'.submatch(0).'" +"%B %d, %Y"')/g

\=system() ................ calls any system command
date -d ................... use a parameter as date input
.    ...................... used for concatenation
+"%B %d, %Y" .............. date format we want

Update

I have just read a comment from Filipe Brandenburger giving us a useful update, he says:
For the replacement, also possible to use Vim functions strftime() and strptime(), so you don't need to shell out to an external date binary..

:%s/>\v\zs\d{4}-\d{2}-\d{2}/\=strftime("%B %d, %Y", strptime("%Y-%m-%d", submatch(0)))/g

But on my neovim when I try to use this solution it says: Unknown function "strptime"

Posted on by:

voyeg3r profile

Sérgio Luiz Araújo Silva

@voyeg3r

I am a Free Software enthusiast and a (neo)?vim addicted, I also like shell script, sed, awk, and as you can see I love Regular Expressions.

Discussion

markdown guide
 

Great article, as usual!

For the replacement, also possible to use Vim functions strftime() and strptime(), so you don't need to shell out to an external date binary..

:%s/\v\d{4}-\d{2}-\d{2}/\=strftime("%B %d, %Y", strptime("%Y-%m-%d", submatch(0)))/g
 

Filipe, it seems that my neovim does not have the function "strptime"