vim search for lines that do not start with a particular string

Viewed 1040

I have a file with hundreds of thousands of lines that start with a date, e.g.

2021-02-22... 

but some odd lines do not start that way. My intention is to write a macro to find them and join them with the line above.

How can I search for such lines from within vim?

E.g., if I wanted to find the next matching line in vim, I would type

/^2021

and it would take me to the next line that starts with "2021"

I want to do this, but search for the next non-matching line.

3 Answers

My intention is to write a macro to find them and join them with the line above.

That kind of operation is usually done with :help :global:

:g!/<pattern>/<command>

which executes <command> on each line not matching <pattern>.

In your case, it would look like this:

:g!/^2021/-j

where…

  • ^2021 is your pattern,
  • -j first sets the address to the line above and then joins it with the following one.

You may find this alternative more intuitive:

:g!/^2021/norm! kJ

which essentially uses the normal mode equivalent of :-j.

If you have several years in that file, consider a simple alternation:

:g!/^\(2021\|2020\|2019\)/-j

or a more generic pattern:

:g!/^\d\d\d\d-\d\d-\d\d/-j

You don't have to try to be smart, here, with quantifiers and negative look-behinds and stuff.

Reference:

:help :global
:help :range
:help :join
:help :normal
:help k
:help J
:help /^
:help \d
:help /\|
:help /\(

We can use look around regex in Vim to tackle this kind of question. If I understand you correctly, you want to search a line not starting with 2021, right?

The following search pattern works:

/\v^(2021)@!

A teardown of this search:

  • \v: use magic search, which will simplify the vim regex, see also :h \v.
  • ^: matches start of a line
  • (2021)@!: @! is negative look ahead, i.e., after start of line, the following patter shouldn't be 2021, the parentheses here means a regex group.

This finds and selects a non-empty line that does not start with 2021:

/^[^2]\([^0]\([^2]\([^1]\)\?\)\?\)\?.*

Explanation:

  • [^2] - expect a char that is not 2
  • add other numbers as optional chars with nesting, using \([^<d>]\)\?, where <d> represents a digit
Related