We know how to replace a pattern, but we can do more. Substitute is more powerful than it seems. Break it down.

Replace with match

Sometimes we want to replace a pattern, but we want to keep some parts of it. For example we have a list of machine names, all of them are constructed in this form: {name}-{id}-{location}, and we want to rename them to follow the new naming logic: {location}-{name}-{id}.

titan-13-eu-west
arachnitect-08-eu-west
titan-43-us-east
ventrexia-77-us-west
tryvuulia-03-ap-south
tryvuulia-03-ap-northeast
rugaro-13-eu-central

We can match them with [a-z]\+-[0-9]\{2\}-[a-z-]\+, yes it’s a bit of regular expression magic, but a quick summary:

regexp summary

Now we can group them with (), so we can reference back to the sub-match: \([a-z]\+\)-\([0-9]\{2\}\)-\([a-z-]\+\). Now we have a regular expression with sub-match groups.

There is an option to enable very-magic mode. If we want to use special characters like (){}+, without spamming the patter with \ characters, we can enable magic using \v. With this the pattern we used above can be simplified to: \v([a-z]+)-([0-9]{2})-([a-z-]+). It does the same thing, but without a lot of extra \ characters.

In the replacement part of the substitution, we can refer to sub-match groups with \1, \2, etc.

We have 3 groups:

  • \1: Name.
  • \2: ID.
  • \3: Location.

It’s time to rename out servers: :%s/\v([a-z]+)-([0-9]{2})-([a-z-]+)/\3-\1-\2/g. After this we get what we wanted, all servers are renamed to the new naming format.

eu-west-titan-13
eu-west-arachnitect-08
us-east-titan-43
us-west-ventrexia-77
ap-south-tryvuulia-03
ap-northeast-tryvuulia-03
eu-central-rugaro-13

Upper case, lower case

We can do even more magic with substitution, for example we can generate a “human readable” name for our servers in a report where the name should start with an upper case letter.

Similar to \{number}, we can use markers to change the next or the following letters.

  • \u: Next character made upper case.
  • \U: Following characters made upper case, until \E
  • \l: Next character made lower case.
  • \L: Following characters made lower case, until \E

With this, we can generate a list with a much easier to read names. We start with the new naming format:

eu-west-titan-13
eu-west-arachnitect-08
us-east-titan-43
us-west-ventrexia-77
ap-south-tryvuulia-03
ap-northeast-tryvuulia-03
eu-central-rugaro-13

What we want is a nice format like: Tryvuulia #03 (ap-northeast). With little changes we can use the same regular expression, we as we flipped groups we have this: \v([a-z-]+)-([a-z]+)-([0-9]{2}). As we want to change only the first letter of the name to be upper case, we can use \u, and change the ordering again: :% s/\v([a-z-]+)-([a-z]+)-([0-9]{2})/\u\2 #\3 (\1)/. And finally we got our user friendly list:

Titan #13 (eu-west)
Arachnitect #08 (eu-west)
Titan #43 (us-east)
Ventrexia #77 (us-west)
Tryvuulia #03 (ap-south)
Tryvuulia #03 (ap-northeast)
Rugaro #13 (eu-central)

We know from day 7 how to sort this, so let’s do it:

Arachnitect #08 (eu-west)
Rugaro #13 (eu-central)
Titan #13 (eu-west)
Titan #43 (us-east)
Tryvuulia #03 (ap-northeast)
Tryvuulia #03 (ap-south)
Ventrexia #77 (us-west)