Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vim: sort using multiple patterns

Tags:

regex

vim

sorting

I know that, in vim, I can sort a file using a regular expression to indicate which parts of each row I want to use to consider while sorting using:

:sort 'regex' r

Is it possible to combine more than one expression?

Here you have an example:

INPUT:

bar a 2
foo b 1
bar b 1
foo a 2

:sort '[a-z]' r

foo b 1
bar b 1
bar a 2
foo a 2

sort '[0-9]' r

bar a 2
bar b 1
foo b 1
foo a 2

EXPECTED (maybe something "like" :sort '[A-Z]|[0-9]' r ?):

bar b 1
bar a 2
foo b 1
foo a 2

Please note that a bare "sort" does not work, due to those "a" and "b" which break the digits order

bar a 2
bar b 1
foo a 2
foo b 1

An alternative outside VIM is also accepted, but, for sake of curiosity, I would like to know if it's actually possible to do it within VIM (and if afermative, how ;-)

Many thanks, Regards

like image 259
Carles Sala Avatar asked Jul 02 '13 07:07

Carles Sala


2 Answers

Assuming that you have external sort available, the following should work:

:%!sort -k1,1 -k3,3n

EDIT: Explanation:

-k is used to specify sort keys. -k1,1 implies start sort on key1 and end it key1. -k3,3n implies start sort on key3 and end it key3; n here denotes numeric sort, i.e. compare according to string numerical value.

By default, sort assumes blank to non-blank transition as the field separator. As such, it'd consider the line bar b 1 to comprise of three fields. If the values were delimited by a specific character other than space, say :, you would specify the field-separator by adding -t:.

like image 108
devnull Avatar answered Nov 09 '22 21:11

devnull


There is a flaw in what you are asking for... If you want to sort by the first word AND the number, then you need to somehow specify the order of precedence. In other words, do you want the sorted list to look like this:

bar b 1
bar a 2
foo b 1
foo a 2

or, this:

bar b 1
foo b 1
bar a 2
foo a 2

Obviously, the answer is the first one. But you need to tell vim that! Hence, I can't think of any (sensible) way to do that in one command... But, I can do it in two:

:sort /\d/ r
:sort /[a-z]/ r

By doing the commands in this order, you are specifying that the first word takes priority over the number.

like image 23
Tom Lord Avatar answered Nov 09 '22 21:11

Tom Lord