2

In a fortran code for example, there are lines like

c   write(6,*) "some text"

    write(6,*) "some other text"

How would I search for lines having a write but exclude all lines starting with c or C.

2 Answers 2

5

You can use the regular expression:

^\([^cC].*\)\?write

Or, using "very magic" to simplify a little:

\v^([^cC].*)?write
  1. \v: turns on "very magic" so we don't have to use as many escape characters,
  2. ^: matches a start of the line,
  3. ([^cC].*)?: matches either nothing, or any character that is not a c/C followed by zero or more characters:
    • [^cC]: matches any character that is not a c/C — this is the part that ignores lines that start with c/C,
    • .*: matches a string of any characters of any length (including zero-length) — this part matches the rest of the line preceding the "write",
    • (...)? : makes the entire expression inside the parentheses optional — this part means that lines that start with "write" will still be matched,
  4. write: matches "write"!

UPDATE: As @KarlYngveLervåg points out in the comments, the instances of write that you want to search for will be (almost) always be the first thing on the line, so you could probably get away with using a much simpler regular expression:

^\s*write
  1. ^: matches the start of the line,
  2. \s*: if any whitespace follows, this matches it,
  3. write: matches "write".

UPDATE 2: If you're actually carrying out a :substitute operation, you can use another method, which is to use :vglobal to only perform the :substitute command on lines which don't match a pattern:

:v/^c/s/write/changed
  1. :v/^c/ On all lines that don't match the regular expression ^c i.e. all lines that don't begin with a "c",
  2. s/write/changed Replace "write" with "changed".

The same technique also works with :global, to perform replacements only on lines that do match a regular expression.

5
  • Or, you could just search for ^\s*write, since it is the first thing on the line. Jan 24, 2017 at 15:54
  • @KarlYngveLervåg Oh. I was presuming it also needed to find lines that had write somewhere in the middle.
    – Rich
    Jan 24, 2017 at 16:00
  • 1
    write is a statement in Fortran, and so it may only be preceded by a comment letter or whitespace. Perhaps also, very rarely, a number label, but I don't think so. Thus it would make sense to simplify the regexes accordingly. Of course, your answer is perfectly correct, but I think it is worth mentioning this simplification. Jan 24, 2017 at 19:12
  • 1
    @KarlYngveLervåg Doesn't Fortran allow multiple statements per line? e.g. x=1; y=2; write(*,*)x,y Nevertheless, I agree with you that the simplification is worth mentioning. I'll update my answer.
    – Rich
    Jan 24, 2017 at 21:31
  • Yes, you are right. I forgot about that. Although, I would argue that multiple statements per line is bad practice. Jan 26, 2017 at 21:14
3

If you're going to use this pattern for substitution, you could also use zero-width lookarounds, in particular \@<!:

                                                        /\@<!
\@<!    Matches with zero width if the preceding atom does NOT match just
        before what follows.  Thus this matches if there is no position in the
        current or previous line where the atom matches such that it ends just
        before what follows.  /zero-width {not in Vi}
        Like "(?<!pattern)" in Perl, but Vim allows non-fixed-width patterns.
        The match with the preceding atom is made to end just before the match
        with what follows, thus an atom that ends in ".*" will work.
        Warning: This can be slow (because many positions need to be checked
        for a match).  Use a limit if you can, see below.
        Example                 matches 
        \(foo\)\@<!bar          any "bar" that's not in "foobar"
        \(\/\/.*\)\@<!in        "in" which is not after "//"

For example:

\(^[cC].*\)\@<!write

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.