ThG
ThG

Reputation: 2401

Vim multiple filtering of a file, with 2 filters based upon number values

I do not know if that title will sound adequate …

Let us say I have a file (> 1000 lines) with a homogeneous structure throughout consisting of three "fields" separated by a space :

1. an integer (negative or positive)
   <space>
2. another integer (negative or positive)
   <space>
3. some text (description)

The integers are >-10000 and < 10000

My problem is : how can I

a) filter this file with criteria such as "1st integer <= 1000" AND "2nd integer >=250" AND "text contains : Boston OR New-York"

b) and put the subset in a new buffer, allowing me to read the results and only the results of the filter(s) ?

I wish to do that with Vim only, not knowing if it is feasible or reasonable (anyway it is above my skills)

Thanks


@FDinoff : sorry, I should have done what you suggest, of course :

It could be a chronology with a StartDate, an EndDate, and a Description :

1 -200 -50 Period one in Italy
2 -150 250 Period one in Greece
3  -50  40 Period two in Italy 
4   10  10 Some event in Italy
5   20  20 Event two in Greece

The filter could be : Filter the items where (to mimic SQL) StartDate <=-50 AND EndDate >=0 AND Description contains Greece, with a resulting filter => line 2

Upvotes: 0

Views: 291

Answers (1)

Nikita Kouevda
Nikita Kouevda

Reputation: 5746

The following generic form will match the numeric parts of your format:

^\s*-\?\d\+\s\+-\?\d\+

To implement restrictions on the numbers, replace each -\?\d\+ with a more specific pattern. For example, for <= -50:

-\([5-9][0-9]\|[1-9][0-9]\{2,}\)

That is, - followed by either a 2 digit number where the first digit is >= 5, or a >= 3 digit number.

Similarly, for >= 250:

\(2[5-9][0-9]\|[3-9][0-9]\{2,}\)

Combining the two:

^\s*-\([5-9][0-9]\|[1-9][0-9]\{2,}\)\s\+\(2[5-9][0-9]\|[3-9][0-9]\{2,}\)

If you also need to filter by some pattern in the description, append that:

^\s*-\([5-9][0-9]\|[1-9][0-9]\{2,}\)\s\+\(2[5-9][0-9]\|[3-9][0-9]\{2,}\)\s\+.\{-}Greece

.\{-} is the lazy version of .*.

To filter by this pattern and write the output to a file, use the following:

:g/pattern/.w filename

Thus, to filter by "first number <= -50 AND second number >= 250 AND 'Greece' in description" and write the output to greece.out:

:g/^\s*-\([5-9][0-9]\|[1-9][0-9]\{2,}\)\s\+\(2[5-9][0-9]\|[3-9][0-9]\{2,}\)\s\+.\{-}Greece/.w greece.out

More complex ranges quickly make this even more ridiculous; you're probably better off parsing the file and filtering with something other than regex.

Upvotes: 1

Related Questions