-1

Now I have a text file that looks like this:

{
    int fun(int a, int b    // match begin this line
       int c) {
       if (a == 0) {
          a = 1;
       } else {
          a = -1;
       }
       return 0;
    }    // mathc end this line
}

{
    int funNoMatch(int a, int b
       int c) {
       return 0;
    }
}

How can I use vim regex to match the entire fun() function in vim?

I can use the following regex to match lines until the left brace of the fun() function:

/^ int fun\_[^{]*{

But... I cannot match lines until the right brace of the fun() function.

I can also use "\_", but it cannot work in this situation.

I want only the fun() function to be matched and do NOT want funNoMatch to be matched.

And I want to match them in Vim by vim regex.

Can anyone can help me?

NOTE:

You can assume the beginning and end of the function have the same indent level.

some good friends have given me some other method to solve my problem and thanks, but I also want to know whether the RegEx can do the same thing or not by the same indent level

blueswhen
  • 1
  • 3
  • 2
    Regex is not suited to selecting matching nested pairs. (See http://stackoverflow.com/questions/133601/can-regular-expressions-be-used-to-match-nested-patterns for details.) – Amber Jun 11 '13 at 01:54
  • Not regex, but you can write a vimrc function for that.. – vidit Jun 11 '13 at 01:58
  • 3
    Also, you can use `%` in the visual mode to jump to the matching bracket. – perreal Jun 11 '13 at 01:59
  • I think it can, because the begin of the function and the end of the function also have the same indent, you can use this to match them. – blueswhen Jun 11 '13 at 01:59
  • 1
    How do you want to "_select_" the function? Will you be putting your cursor at the beginning of the function and you want to select the _rest_ of the function? Or are you hoping to be able to enter the name of the function with a command and have Vim find it for you? Your question needs more detail. – jahroy Jun 11 '13 at 02:23
  • I have a source file and there are hundreds of function like the sample what i write in it, and I want to find several functions which the function name inculde some features in them. Then I can use %s/xxxx//g to delete them. Then I can focus on remaining important functions. – blueswhen Jun 11 '13 at 02:42
  • Check out the answer I just added... It should be easy to get what you want using that as a starting point. – jahroy Jun 11 '13 at 02:43

2 Answers2

2

Regular expressions don't seem to be the right tool. Here is how you could do it with a macro:

qq        " start recording in register q
/fun(<CR> " jump to next fun(
ma        " create mark a here
/{<CR>    " jump to next {
%         " jump to closing }
d'a       " delete from here to mark a
q         " stop recording

Once you are done, you only need to execute that macro 100 (or some arbitrary number) times with

100@q

A good thing with macros is that they are saved between sessions so if you ever need to do that gymnastic later, @q will still be there for you.


Another "one shot" solution is to use my beloved :global and :normal commands:

:g/fun(/norm! ma/{^M%d'a

The ^M is inserted with <C-v><CR>.


Combining macros and :global, we can have a pretty cool tool: we use :global to match fun( and we apply a function name-agnostic macro. Let's see…

First, we position the cursor on a fun( line, how we do it doesn't matter.

Then, we record the macro:

qq        " start recording in register q
ma        " create mark a here
/{<CR>    " jump to next {
%         " jump to closing }
d'a       " delete from here to mark a
q         " stop recording

Then, we apply the macro to every line matching fun(:

:g/fun(/norm! @q

Next time, the match could be foobar( or whatever and you would only have to do:

:g/foobar(/norm! @q

Not much typing, not much thinking, instantaneous… nice.


Cutting all those functions and pasting them in another buffer follows the same logic:

:g/fun(/norm! ma/{^M%"Xd'a
:tabnew
"xp

where we append all the functions to the x register (using capitalized X), open a new empty buffer in a new tab and paste the content of the x register.

romainl
  • 186,200
  • 21
  • 280
  • 313
  • Very good, thank you. I don't know about recording function before. and I also have a question, after the last command ":g/fun(/norm! ma/{^M%"Xd'a | tabnew | "xp" be executed, what should I do to paste all content of the x register to other new file? – blueswhen Jun 11 '13 at 08:05
  • But Nothing happen after i execute this command, and if it can paste to other new file, what's the new file name, Needn't I specify a name? – blueswhen Jun 11 '13 at 08:18
  • I'm sorry, that command doesn't work as a oneliner but it works perfectly when you do it in three steps: 1. `:g/fun(/norm! ma/{^M%"Xd'a` 2. `tabnew` 3. `"xp`. I'll revise my answer. Anyway, you don't need to name your buffer, this can be done later, if you decide to save it: `:w fun-only.txt`. – romainl Jun 11 '13 at 08:53
  • But Maybe the Regular expressions is not a good method, But I really want to know whether it is possible to use RegEx to match the entire function by the same indent level or not. – blueswhen Jun 11 '13 at 09:16
  • Yes, it's probably possible but I don't think it's *realistically* possible. Matching a line with a 4 spaces indent, capturing that indent and reusing it elsewhere in the pattern seems doable but the time needed to come up with the right pattern expression makes the whole idea very impractical IMO. Vim is all about efficiency and regex are not always the most efficient tool. – romainl Jun 11 '13 at 10:33
  • Maybe you are right, But I also want to know more than one skill. Now I can use regex `"\_[^{]*{"` to find the left brance. But I cannot match the right brance. Because if I use regex `"\_.*\n4space}"` to match, it only match the last `"\n4space}"` in the source file. I want to match the first string `"\n4space}"` from the beginning of the function. This is my real problem. – blueswhen Jun 11 '13 at 11:36
  • Yeah, you are facing exactly the same problem I faced in my tests trying to answer your question (`sbmatch()` didn't help, for example) and that's my point: it's too hard and maybe impossible to come up with a pattern to do what you want so it's better to not waste your time. Vim is all about efficiency, not about encyclopedic knowledge: my opinion, it's only an opinion, is that, even if it's possible, it shouldn't be tried because there are much better ways. Even Vim itself doesn't use regular expressions for that. – romainl Jun 11 '13 at 12:11
  • 1
    @blueswhen - If you want to know how to do it with RegEx, roll up your sleeves and figure it out. Two people have already spent a significant amount of time helping you solve your problem. Both have told you that **A.)** RegEx is not the right tool for the job and **B.)** It is not worth the time and effort to figure it out with RegEx when better tools and methods exist. – jahroy Jun 11 '13 at 20:18
  • ok,I know it and thanks all of them, I'm a new guy, what should i do? close the question or what else? – blueswhen Jun 12 '13 at 00:08
  • No, don't close the question. Just accept the idea that regular expressions are not an universally relevant answer, or the answer to your current question, and move on. – romainl Jun 12 '13 at 05:04
0

Here's how you could delete all functions whose names contain RemoveThisFunction:

nnoremap Q /RemoveThisFunction<CR>0v/{<CR>%d

Using the above, you could just hit Q a bunch of times until all your functions are gone...

If you want more help, you'll have to tell us how you will find the functions you want to delete.


If you can assume that the cursor is already at the beginning of the function, you can do the following...

Create a mapping that is triggered by pressing FF:

:nnoremap FF v/{<CR>%

The mapping will do the following:

 -  enter visual mode
 -  search for the next brace
 -  go to the matching brace

* You can add a d to the end of the map command to actually delete the text...


If you want to use your last search pattern to find the matching text, you could do something like this:

:nnoremap EE //<CR>0v/{<CR>%

In other words:

 -  find the last search term
 -  go there  (get to the start of the function)
 -  go to the beginning of the line
 -  enter visual mode
 -  find the next brace
 -  go there
 -  move to the matching close brace

All the text from the beginning of the function will be selected (in visual mode).

You could add a d to the end of the map command to delete the actual text.

jahroy
  • 22,322
  • 9
  • 59
  • 108
  • sorry, it cannot help me, I said there are hundreds of functions need to delete, if only one or two functions, i can use your method or use "%" directly. But they are too many, and i want a method which can finish this automatically. – blueswhen Jun 11 '13 at 02:55
  • That's why I'm trying to show you how to make this command work with a regex search... First you figure out how to find your functions with a search pattern, then you use the mapped command to get rid of them. You could easily combine a couple mappings to make it all happen with a single keystroke. – jahroy Jun 11 '13 at 02:57
  • Can you say it more detailedly, How can i combine a couple mappings to make it all happen with a single keystroke? I find the last search pattern will change after the EE command executed – blueswhen Jun 11 '13 at 03:18
  • See the edit I just made (at the top of the answer). You can hardcode your search pattern into the mapping, then use it repeatedly... That way you don't have to worry about the last search getting overwritten. – jahroy Jun 11 '13 at 03:32
  • Use [num]Q command to repeat Q command, is it right? But I find it only delete the last match function, not all of ones matched. – blueswhen Jun 11 '13 at 03:44
  • You are right, if I hold "Q" keystroke, Then the command will be executed repeatedly and correctly. It also can solve my problem. But I also want to know whether the regex can do the same thing or not. And if I don't want to delete them, i want to copy them and paste them to other file, Can your method also can do it? – blueswhen Jun 11 '13 at 03:57