19

I need a Regex that will match a java method declaration. I have come up with one that will match a method declaration, but it requires the opening bracket of the method to be on the same line as the declaration. If you have any suggestions to improve my regex or simply have a better one then please submit an answer.

Here is my regex: "\w+ +\w+ *\(.*\) *\{"

For those who do not know what a java method looks like I'll provide a basic one:

int foo()
{

}

There are several optional parts to java methods that may be added as well but those are the only parts that a method is guaranteed to have.

Update: My current Regex is "\w+ +\w+ *\([^\)]*\) *\{" so as to prevent the situation that Mike and adkom described.

Anton
  • 12,285
  • 20
  • 64
  • 84

15 Answers15

24
(public|protected|private|static|\s) +[\w\<\>\[\]]+\s+(\w+) *\([^\)]*\) *(\{?|[^;])

I think that the above regexp can match almost all possible combinations of Java method declarations, even those including generics and arrays are return arguments, which the regexp provided by the original author did not match.

Georgios Gousios
  • 2,405
  • 1
  • 24
  • 34
  • I think that would do it. It will also exclude constructors too, which is nice :-) – James Camfield May 11 '09 at 11:04
  • 2
    What's the `\s` at the beginning for? Why would something start with two spaces? Prevents it from matching package scope unless the indentation is just right. – idbrii Jul 26 '12 at 14:08
  • 1
    @seba229's answer includes some keywords that yours does not – Rich Dec 16 '13 at 13:35
  • 1
    You're missing `native` from that list – Jonathan Leitschuh Sep 25 '15 at 18:02
  • Slight modification to account for things like `public Map all() {` as well as constructors like `public Cache()` : `+[\w\<\>\[\]\,\s]*\s*(\w+) *\([^\)]*\) *(\{?|[^;])` – Shanerk Jun 03 '19 at 22:44
  • 1
    @Shane your regex fails to match the last character of the method name. `(public|protected|private|static|\s) +[\w\<\>\[\],\s]+\s+(\w+) *\([^\)]*\) *(\{?|[^;])` works for me. – Gili Jun 28 '19 at 18:02
  • That makes sense, yeah * often causes problems. – Shanerk Jun 28 '19 at 20:27
7

I also needed such a regular expression and came up with this solution:

(?:(?:public|private|protected|static|final|native|synchronized|abstract|transient)+\s+)+[$_\w<>\[\]\s]*\s+[\$_\w]+\([^\)]*\)?\s*\{?[^\}]*\}?

This grammar and Georgios Gousios answer have been useful to build the regex.

EDIT: Considered tharindu_DG's feedback, made groups non-capturing, improved formatting.

sbaltes
  • 489
  • 1
  • 9
  • 17
  • Why is threadsafe in the regex? It isn't a modifier in Java. Tried looking at the spec http://docs.oracle.com/javase/specs/jls/se7/html/jls-18.html and/or http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html – Aseem Bansal Oct 17 '15 at 16:13
5

After looking through the other answers, here is what I came up with:

#permission
   ^[ \t]*(?:(?:public|protected|private)\s+)?
#keywords
   (?:(static|final|native|synchronized|abstract|threadsafe|transient|{#insert zJRgx123GenericsNotInGroup})\s+){0,}
#return type
   #If return type is "return" then it's actually a 'return funcName();' line. Ignore.
   (?!return)
   \b([\w.]+)\b(?:|{#insert zJRgx123GenericsNotInGroup})((?:\[\]){0,})\s+
#function name
   \b\w+\b\s*
#parameters
   \(
      #one
         \s*(?:\b([\w.]+)\b(?:|{#insert zJRgx123GenericsNotInGroup})((?:\[\]){0,})(\.\.\.)?\s+(\w+)\b(?![>\[])
      #two and up
         \(\s*(?:,\s+\b([\w.]+)\b(?:|{#insert zJRgx123GenericsNotInGroup})((?:\[\]){0,})(\.\.\.)?\s+(\w+)\b(?![>\[])\s*){0,})?\s*
   \)
#post parameters
   (?:\s*throws [\w.]+(\s*,\s*[\w.]+))?
#close-curly (concrete) or semi-colon (abstract)
   \s*(?:\{|;)[ \t]*$

Where {#insert zJRgx123GenericsNotInGroup} equals

`(?:<[?\w\[\] ,.&]+>)|(?:<[^<]*<[?\w\[\] ,.&]+>[^>]*>)|(?:<[^<]*<[^<]*<[?\w\[\] ,.&]+>[^>]*>[^>]*>)`

Limitations:

  • ANY parameter can have an ellipsis: "..." (Java allows only last)
  • Three levels of nested generics at most: (<...<...<...>...>...> okay, <...<...<...<...>...>...>...> bad). The syntax inside generics can be very bogus, and still seem okay to this regex.
  • Requires no spaces between types and their (optional) opening generics '<'
  • Recognizes inner classes, but doesn't prevent two dots next to each other, such as Class....InnerClass

Below is the raw PhraseExpress code (auto-text and description on line 1, body on line 2). Call {#insert zJRgxJavaFuncSigThrSemicOrOpnCrly}, and you get this:

^[ \t]*(?:(?:public|protected|private)\s+)?(?:(static|final|native|synchronized|abstract|threadsafe|transient|(?:<[?\w\[\] ,&]+>)|(?:<[^<]*<[?\w\[\] ,&]+>[^>]*>)|(?:<[^<]*<[^<]*<[?\w\[\] ,&]+>[^>]*>[^>]*>))\s+){0,}(?!return)\b([\w.]+)\b(?:|(?:<[?\w\[\] ,&]+>)|(?:<[^<]*<[?\w\[\] ,&]+>[^>]*>)|(?:<[^<]*<[^<]*<[?\w\[\] ,&]+>[^>]*>[^>]*>))((?:\[\]){0,})\s+\b\w+\b\s*\(\s*(?:\b([\w.]+)\b(?:|(?:<[?\w\[\] ,&]+>)|(?:<[^<]*<[?\w\[\] ,&]+>[^>]*>)|(?:<[^<]*<[^<]*<[?\w\[\] ,&]+>[^>]*>[^>]*>))((?:\[\]){0,})(\.\.\.)?\s+(\w+)\b(?![>\[])\s*(?:,\s+\b([\w.]+)\b(?:|(?:<[?\w\[\] ,&]+>)|(?:<[^<]*<[?\w\[\] ,&]+>[^>]*>)|(?:<[^<]*<[^<]*<[?\w\[\] ,&]+>[^>]*>[^>]*>))((?:\[\]){0,})(\.\.\.)?\s+(\w+)\b(?![>\[])\s*){0,})?\s*\)(?:\s*throws [\w.]+(\s*,\s*[\w.]+))?\s*(?:\{|;)[ \t]*$

Raw code:

zJRgx123GenericsNotInGroup -- To precede return-type    (?:<[?\w\[\] ,.&]+>)|(?:<[^<]*<[?\w\[\] ,.&]+>[^>]*>)|(?:<[^<]*<[^<]*<[?\w\[\] ,.&]+>[^>]*>[^>]*>)  zJRgx123GenericsNotInGroup
zJRgx0OrMoreParams  \s*(?:{#insert zJRgxParamTypeName}\s*(?:,\s+{#insert zJRgxParamTypeName}\s*){0,})?\s*   zJRgx0OrMoreParams
zJRgxJavaFuncNmThrClsPrn_M_fnm -- Needs zvFOBJ_NAME (?<=\s)\b{#insert zvFOBJ_NAME}{#insert zzJRgxPostFuncNmThrClsPrn}   zJRgxJavaFuncNmThrClsPrn_M_fnm
zJRgxJavaFuncSigThrSemicOrOpnCrly -(**)-    {#insert zzJRgxJavaFuncSigPreFuncName}\w+{#insert zzJRgxJavaFuncSigPostFuncName}    zJRgxJavaFuncSigThrSemicOrOpnCrly
zJRgxJavaFuncSigThrSemicOrOpnCrly_M_fnm -- Needs zvFOBJ_NAME    {#insert zzJRgxJavaFuncSigPreFuncName}{#insert zvFOBJ_NAME}{#insert zzJRgxJavaFuncSigPostFuncName}  zJRgxJavaFuncSigThrSemicOrOpnCrly_M_fnm
zJRgxOptKeywordsBtwScopeAndRetType  (?:(static|final|native|synchronized|abstract|threadsafe|transient|{#insert zJRgx123GenericsNotInGroup})\s+){0,}    zJRgxOptKeywordsBtwScopeAndRetType
zJRgxOptionalPubProtPriv    (?:(?:public|protected|private)\s+)?    zJRgxOptionalPubProtPriv
zJRgxParamTypeName -(**)- Ends w/ '\b(?![>\[])' to NOT find <? 'extends XClass'> or ...[]>  (*Original: zJRgxParamTypeName, Needed by: zJRgxParamTypeName[4FQPTV,ForDel[NmsOnly,Types]]*){#insert zJRgxTypeW0123GenericsArry}(\.\.\.)?\s+(\w+)\b(?![>\[])   zJRgxParamTypeName
zJRgxTypeW0123GenericsArry -- Grp1=Type, Grp2='[]', if any  \b([\w.]+)\b(?:|{#insert zJRgx123GenericsNotInGroup})((?:\[\]){0,}) zJRgxTypeW0123GenericsArry
zvTTL_PRMS_stL1c    {#insert zCutL1c}{#SETPHRASE -description zvTTL_PRMS -content {#INSERTCLIPBOARD} -autotext zvTTL_PRMS -folder ctvv_folder}  zvTTL_PRMS_stL1c
zvTTL_PRMS_stL1cSvRstrCB    {#insert zvCB_CONTENTS_stCB}{#insert zvTTL_PRMS_stL1c}{#insert zSetCBToCB_CONTENTS} zvTTL_PRMS_stL1cSvRstrCB
zvTTL_PRMS_stPrompt {#SETPHRASE -description zvTTL_PRMS -content {#INPUT -head How many parameters? -single} -autotext zvTTL_PRMS -folder ctvv_folder}  zvTTL_PRMS_stPrompt
zzJRgxJavaFuncNmThrClsPrn_M_fnmTtlp -- Needs zvFOBJ_NAME, zvTTL_PRMS    (?<=[ \t])\b{#insert zvFOBJ_NAME}\b\s*\(\s*{#insert {#COND -if {#insert zvTTL_PRMS} = 0 -then z1slp -else zzParamsGT0_M_ttlp}}\)    zzJRgxJavaFuncNmThrClsPrn_M_fnmTtlp
zzJRgxJavaFuncSigPostFuncName   {#insert zzJRgxPostFuncNmThrClsPrn}(?:\s*throws \b(?:[\w.]+)\b(\s*,\s*\b(?:[\w.]+)\b))?\s*(?:\{|;)[ \t]*$   zzJRgxJavaFuncSigPostFuncName
zzJRgxJavaFuncSigPreFuncName    (*If a type has generics, there may be no spaces between it and the first open '<', also requires generics with three nestings at the most (<...<...<...>...>...> okay, <...<...<...<...>...>...>...> not)*)^[ \t]*{#insert zJRgxOptionalPubProtPriv}{#insert zJRgxOptKeywordsBtwScopeAndRetType}(*To prevent 'return funcName();' from being recognized:*)(?!return){#insert zJRgxTypeW0123GenericsArry}\s+\b  zzJRgxJavaFuncSigPreFuncName
zzJRgxPostFuncNmThrClsPrn   \b\s*\({#insert zJRgx0OrMoreParams}\)   zzJRgxPostFuncNmThrClsPrn
zzParamsGT0_M_ttlp -- Needs zvTTL_PRMS  {#insert zJRgxParamTypeName}\s*{#insert {#COND -if {#insert zvTTL_PRMS} = 1 -then z1slp -else zzParamsGT1_M_ttlp}}  zzParamsGT0_M_ttlp
zzParamsGT1_M_ttlp  {#LOOP ,\s+{#insert zJRgxParamTypeName}\s* -count {#CALC {#insert zvTTL_PRMS} - 1 -round 0 -thousands none}}    zzParamsGT1_M_ttlp
aliteralmind
  • 19,847
  • 17
  • 77
  • 108
  • 1
    Have to give props to RegexBuddy for helping me work through this: http://www.regexbuddy.com/ – aliteralmind Nov 28 '13 at 14:46
  • Impressively thorough answer! I tried it in my .gitconfig, and got a "fatal: bad config line" error. I tried escaping the backslashes, and moved up to a "fatal: Invalid regexp to look for hunk header" error. Hmm. Maybe I need to learn what needs to be escaped in .gitconfig. – LarsH Oct 25 '18 at 18:49
  • After skimming the git-config docs about what needs to be escaped, I surrounded the whole thing with double quotes, so that the semicolon wouldn't terminate the value. Still got the "fatal: Invalid regexp to look for hunk header" error. – LarsH Oct 25 '18 at 18:56
4

Have you considered matching the actual possible keywords? such as:

(?:(?:public)|(?:private)|(?:static)|(?:protected)\s+)*

It might be a bit more likely to match correctly, though it might also make the regex harder to read...

Mike Stone
  • 44,224
  • 30
  • 113
  • 140
2

(public|private|static|protected|abstract|native|synchronized) +([a-zA-Z0-9<>._?, ]+) +([a-zA-Z0-9_]+) *\\([a-zA-Z0-9<>\\[\\]._?, \n]*\\) *([a-zA-Z0-9_ ,\n]*) *\\{

The Regex above will detect all possible java method definitions. Tested on lot's of source code files. To include constructors as well use the below regex :

(public|private|static|protected|abstract|native|synchronized) +([a-zA-Z0-9<>._?, ]*) +([a-zA-Z0-9_]+) *\\([a-zA-Z0-9<>\\[\\]._?, \n]*\\) *([a-zA-Z0-9_ ,\n]*) *\\{

Souvik Das
  • 51
  • 1
2

This will pick the name of method not the whole line.

(?<=public static void )\w+|(?<=private static void )\w+|(?<=protected static void )\w+|(?<=public void )\w+|(?<=private void )\w+|(?<=protected void )\w+|(?<=public final void)\w+|(?<=private final void)\w+|(?<=protected final void)\w+|(?<=private void )\w+|(?<=protected void )\w+|(?<=public static final void )\w+|(?<=private static final void )\w+|(?<=public final static void )\w+|(?<=protected final static void )\\w+|(?<=private final static void )\w+|(?<=protected final static void )\w+|(?<=void )\w+|(?<=private static )\w+
Abdullah Khan
  • 1,365
  • 15
  • 15
2

I'm pretty sure Java's regex engine is greedy by default, meaning that "\w+ +\w+ *\(.*\) *\{" will never match since the .* within the parenthesis will eat everything after the opening paren. I recommend you replace the .* with [^)], this way you it will select all non-closing-paren characters.

NOTE: Mike Stone corrected me in the comments, and since most people don't really open the comments (I know I frequently don't notice them):

Greedy doesn't mean it will never match... but it will eat parens if there are more parens after to satisfy the rest of the regex... so for example "public void foo(int arg) { if (test) { System.exit(0); } }" will not match properly...

akdom
  • 32,264
  • 27
  • 73
  • 79
  • 1
    Greedy doesn't mean it will never match... but it will eat parens if there are more parens after to satisfy the rest of the regex... so for example "public void foo(int arg) { if (test) { System.exit(0); } }" will not match properly... – Mike Stone Sep 16 '08 at 02:00
2

I came up with this:

\b\w*\s*\w*\(.*?\)\s*\{[\x21-\x7E\s]*\}

I tested it against a PHP function but it should work just the same, this is the snippet of code I used:

function getProfilePic($url)
 {
    if(@open_image($url) !== FALSE)
     {
        @imagepng($image, 'images/profiles/' . $_SESSION['id'] . '.png');
        @imagedestroy($image);
        return TRUE;
     }
    else 
     {
        return FALSE;
     }
 }

MORE INFO:

Options: case insensitive

Assert position at a word boundary «\b»
Match a single character that is a “word character” (letters, digits, etc.) «\w*»
   Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.) «\s*»
   Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Match a single character that is a “word character” (letters, digits, etc.) «\w*»
   Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Match the character “(” literally «\(»
Match any single character that is not a line break character «.*?»
   Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
Match the character “)” literally «\)»
Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.) «\s*»
   Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Match the character “{” literally «\{»
Match a single character present in the list below «[\x21-\x7E\s]*»
   Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
   A character in the range between ASCII character 0x21 (33 decimal) and ASCII character 0x7E (126 decimal) «\x21-\x7E»
   A whitespace character (spaces, tabs, line breaks, etc.) «\s»
Match the character “}” literally «\}»


Created with RegexBuddy
UnkwnTech
  • 88,102
  • 65
  • 184
  • 229
1

This is for a more specific use case but it's so much simpler I believe its worth sharing. I did this for finding 'public static void' methods i.e. Play controller actions, and I did it from the Windows/Cygwin command line, using grep; see: https://stackoverflow.com/a/7167115/34806

cat Foobar.java | grep -Pzo '(?s)public static void.*?\)\s+{'

The last two entries from my output are as follows:

public static void activeWorkEventStations (String type,
            String symbol,
            String section,
            String day,
            String priority,
            @As("yyyy-MM-dd") Date scheduleDepartureDate) {
public static void getActiveScheduleChangeLogs(String type,
            String symbol,
            String section,
            String day,
            String priority,
            @As("yyyy-MM-dd") Date scheduleDepartureDate) {
Community
  • 1
  • 1
Dexygen
  • 12,287
  • 13
  • 80
  • 147
1

As of git 2.19.0, the built-in regexp for Java now seems to work well, so supplying your own may not be necessary.

"!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
"^[ \t]*(([A-Za-z_][A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$"

(The first line seems to be for filtering out lines that resemble method declarations but aren't.)

LarsH
  • 27,481
  • 8
  • 94
  • 152
1

A tip:

If you are going to write the regex in Perl, please use the "xms" options so that you can leave spaces and document the regex. For example you can write a regex like:

 m{\w+ \s+      #return type
   \w+ \s*      #function name
   [(] [^)]* [)] #params
   \s* [{]           #open paren
  }xms

One of the options (think x) allows the # comments inside a regex. Also use \s instead of a " ". \s stands for any "blank" character. So tabs would also match -- which is what you would want. In Perl you don't need to use / /, you can use { } or < > or | |.

Not sure if other languages have this ability. If they do, then please use them.

0

I built a vim regex to do this for ctrlp/funky based on Georgios Gousios's answer.

    let regex = '\v^\s+'                " preamble
    let regex .= '%(<\w+>\s+){0,3}'     " visibility, static, final
    let regex .= '%(\w|[<>[\]])+\s+'    " return type
    let regex .= '\w+\s*'               " method name
    let regex .= '\([^\)]*\)'           " method parameters
    let regex .= '%(\w|\s|\{)+$'        " postamble

I'd guess that looks like this in Java:

^\s+(?:<\w+>\s+){0,3}(?:[\w\<\>\[\]])+\s+\w+\s*\([^\)]*\)(?:\w|\s|\{)+$
idbrii
  • 10,975
  • 5
  • 66
  • 107
0

I found seba229's answer useful, it captures most of the scenarios, but not the following,

public <T> T name(final Class<T> x, final T y)

This regex will capture that also.

((public|private|protected|static|final|native|synchronized|abstract|transient)+\s)+[\$_\w\<\>\w\s\[\]]*\s+[\$_\w]+\([^\)]*\)?\s*

Hope this helps.

tharindu_DG
  • 8,900
  • 6
  • 52
  • 64
0
(public|private|static|protected) ([A-Za-z0-9<>.]+) ([A-Za-z0-9]+)\(

Also, here's a replace sequence you can use in IntelliJ

$1 $2 $3(

I use it like this:

$1 $2 aaa$3(

when converting Java files to Kotlin to prevent functions that start with "get" from automatically turning into variables. Doesn't work with "default" access level, but I don't use that much myself.

user1122069
  • 1,767
  • 1
  • 24
  • 52
0

This can completely define and separate a java function

(?<access>public|private|protected)?\s*(?<static>static|non-static)?\s*(?<final>final|non-final)?\s*(?<type>void|\w+)\s+(?<name>[a-zA-Z0-9_]+)\((?<parameter>.*?)\)\s*\{(?s)(?<body>.*?)\}

Java function

Compatible with:

  • PCRE2 (PHP >= 7.3)
  • JAVA8

Groups:

  • access: public
  • static: static
  • final: non-final
  • type: void
  • name: main
  • parameter: String[] args
  • body: // This is a Java function
Mohamed Rahal
  • 61
  • 1
  • 3