Regex to find the last "}" on last line - regex

I am having trouble writing a regex for the last "}" in the last line in a file.
For example, if this is the file:
/*
blas
*/
import bla;
public class bla {
...
public void bla (blas){
...
}
...
} //this is the "}"
Can anyone help?
It's preferable if the solution doesn't rely on indentation or lack of additional comments at the end (I think it's fair to assume that even if there are comments at the end then they don't contain "}"), but right now I'm prepared to take anything.
The best I could do was: ^}$ but that relies on proper indentation.
Thanks a lot in advance.

No need for multi-line modifiers, just use this }(?=[^}]*$)
This would find the last } in the file.
If you want to force a find only on the last line it's (?m)^.*(}).*\z
or, if the last visible line it's (?m)^.*(}).*\s*\z

Simple as halwa!
use this:
}.*?$
Example here: https://regex101.com/r/oM3tW3/1
If you want to return the match, use:
(}).*?$

Related

Having a problem with multiple hyphens in a multistring regex match in Perl

I am downloading a webpage and converting into a string using LWP::Simple. When I copy the results into an editor I find multiple instances of the pattern I'm looking for "data-src-hq".
While I'm trying to do something more complex using regex I am starting in baby steps so I can properly learn how to use regex, I started off with just to match "data-src-hq" with the following code:
if($html =~ /data-src-hq/ism)
{
print "match\n";
}
else
{
print "nope\n";
}
My code returns "nope". However, if I modify the pattern search to just "data" or "data-src" I do get a match. The same happens no matter how I use and combine the string and multiline modifier.
My understanding is that a hyphen is not a special character unless it's within brackets, am I missing something simple?
How to fix this?
You are likely getting two outputs, one of match and one of nope. Your code is missing the keyword else:
See your code's current execution here
if($html =~ /data-src-hq/ism)
{
print "match\n";
}
{
print "nope\n";
}
Should be:
See this code's execution here
if($html =~ /data-src-hq/ism)
{
print "match\n";
}
else {
print "nope\n";
}
Otherwise, your code is fine and works to identify whether data-src-hq exists in $html.
So why does your existing code output nope?
That's because {} is a basic block (see Basic BLOCKs in Perl's documentation). An excerpt from the documentation:
A BLOCK by itself (labeled or not) is semantically equivalent to a
loop that executes once. Thus you can use any of the loop control
statements in it to leave or restart the block. (Note that this is NOT
true in eval{}, sub{}, or contrary to popular belief do{} blocks,
which do NOT count as loops.) The continue block is optional.

Deleting comments in a large file

I am trying to delete a bunch of comments that are all in the following format:
/**
* #ngdoc
... comment body (delete me, too!)
*/
I have tried using this command: %s/\/**\n * #ngdoc.\{-}*\///g
Here is the regex without the patterns: %s/pattern1.\{-}pattern2//g
Here are the individual patterns: \/**\n * #ngdoc and *\/
When I try my pattern in vim I get the following error:
E871: (NFA regexp) Can't have a multi follow a multi !
E61: Nested *
E476: Invalid command
Thanks for any help with this regexp nightmare!
Instead of trying to cram this into one complex regex, it's much easier to search for the start of a comment and delete from there on to the end of a comment
:g/^\/\*\*$/,/\*\/$/d_
This breaks down into
:g start a global command
/^\/\*\*$/ search for start of a comment: <sol>/**<eol>
,/^\*\/$/ extend the range to the end of a comment: <sol>*/<eol>
d delete the range
_ use the black hole register (performance optimization)
Your problem is you have \{-} followed by * which are the multis referenced in the error message. Quote the *:
%s/\/\*\*\n \* #ngdoc\_.\{-}\*\/\n//g
Using embedded newlines in the pattern is the wrong approach. You should instead use an address range. Something like:
sed '\#^/\*\*$#,\#^\*/$#d' file
This will delete all lines starting from one that matches /** anchored at column 1 to the line matching */ anchored at column 1. If your comments are well behaved (eg, no trailing space after /**), this should do what you want.
Try this using gc to be careful when deleting
%s/\v\/\*\*\n\s\*\s\#ngdoc\n((\s*\n)?(\s\*.*\n)?){-}\s?\*\///gc
Match comments like
/**
* #ngdoc
* ... comment body (delete me, too!)
*
*/
My approached consists of using a macro:
qa/\/\*\*<enter><shift-v>/\*\/<enter>d
qa ........ starts recording macro "a"
/\/\*\* ... searches for the comment beginning
<Enter> ... use Ctrl-v Enter
V ......... starts visual block (until...)
/\*\/ ..... end of your comment
<Enter> ... Ctrl-v Enter agai
d ......... it will delete selected area
In order to isert etc presse followed by the keyword you want.

Regex replace special comments

So few months ago one of my colleagues left. He used to comment all his code this way:
//----------------------------
// COMMENT
//----------------------------
private void func()...
So each comment, instead of using 1 line at most, uses 4 lines (including break line), which drives me crazy. I'm trying to create a Regex which I can remove this comment safely and replace it. The above code should like this way:
// COMMENT
private void func()...
I thought of just removing each one of the '//----------------------------' but it leaves me with many empty lines as well as break line between the comment and the actual line which to be described. Any help will be well appreciated.
EDIT
Note one:
Our project is written in Visual Studio
Note two: Some comments may contain more than 1 line of comment, example:
//----------------------------
// LINE 1 COMMENT
// LINE 2 COMMENT
//----------------------------
This expression matches your case and any 3 lines of comments where the first and the last ones have trailing -:
((\s|\t)*\/{2,})(.*[-]+)(\r?\n)((\1(.*)\4?)+)\4\1\3\4?
Try it here
And then you can replace it with:
\5 (or $5)
EDIT: for multi-line comments.
Here's a Regular Expression that you can use to strip out the excess (decorative) comment lines and convert these bulky comments into one-liners.
It also supports indentation and multi-line comments using this style:
//----------------------------
// LINE 1 COMMENT
// LINE 2 COMMENT
//----------------------------
private void func()...
Find:
(( |\t)*?\r\n)?( |\t)*?//-+(\r\n( |\t)*?// .+)+\r\n( |\t)*?//-+\r\n
Replace With:
\4
(Replace \4 with $4 if the replace failed)
Good luck!

How to find only patterns that are not commented?

I have some code where the same condition ABC is used as part of an if clause, at the end of it (as a comment) and in obsolete sections (which I do not want to remove yet). An example could look like this:
if (ABC) //this is the only line that should be matched, this comment should not change the outcome of the search
{
lots of code
} // if (ABC)
//if (ABC)
// {
// lots of obsolete code
// } // if (ABC)
How can I tell vim to search for the pattern ABC only where is is not commented out via // occurring before it on the same line?
^.*\(\/\/\)\#!.*ABC did not work, because the .* are also fulfilled by // and ^\(\/\/\)\#!*ABC complains about "Nested *".
Any ideas?
Thank you
for the example in your question, this line works:
/\v(\/\/.*)#<!ABC
or without very magic:
/\(\/\/.*\)\#<!ABC

Correcting Wrong Marker Folding in VIM

I mistakenly did marker folding to my .vimrc:
{{{8 #CS
something..
}}}8
{{{9 #Math
...
}}}9
... many more!
I need to switch the format to "#SOMETHING {{{NUMBER" like:
#CS {{{8
something..
}}}8
#Math {{{9
...
}}}9
... many more!
What is wrong in the following code:
:%s$/({{{\d/) /(#[:alpha:]/)$\2 \1$g
[Solution]
%s$\({{{\d\) \(#[[:alnum:]]*\)$\2 \1$g
You forgot to escape the parentheses, and the POSIX character classes are only valid within a character class [[:alpha:]]:
:%s$/\({{{\d/\) /\(#[[:alpha:]]/\)$\2 \1$g
Note, however, that your example text doesn't contain any slashes - is this what your sample text is actually like?
The above regex changes this
/{{{8/ /#A/
To this
#A/ {{{8/
:%s/{{{\(\d\) \(.*\)/\2 {{{\1/g
it works, but in your regex I don't understand why do you got a $ after s.