Регулярное выражение, которое будет соответствовать объявлению метода Java
Вопрос
Мне нужно регулярное выражение, которое будет соответствовать объявлению метода java.Я придумал тот, который будет соответствовать объявлению метода, но для этого требуется, чтобы открывающая скобка метода находилась в той же строке, что и объявление.Если у вас есть какие-либо предложения по улучшению моего регулярного выражения или просто есть что-то получше, пожалуйста, отправьте ответ.
Вот мое регулярное выражение: "\w+ +\w+ *\(.*\) *\{"
Для тех, кто не знает, как выглядит java-метод, я приведу базовый:
int foo()
{
}
Есть несколько необязательных частей к методам java, которые также могут быть добавлены, но это единственные части, которые гарантированно должны быть у метода.
Обновить:Мое текущее Регулярное выражение является "\w+ +\w+ *\([^\)]*\) *\{"
чтобы предотвратить ситуацию, которую описали Майк и адком.
Решение
Рассматривали ли вы возможность подбора реальных возможных ключевых слов?такие , как:
(?:(?:public)|(?:private)|(?:static)|(?:protected)\s+)*
Вероятность правильного совпадения может быть немного выше, хотя это также может затруднить чтение регулярного выражения...
Другие советы
(public|protected|private|static|\s) +[\w\<\>\[\]]+\s+(\w+) *\([^\)]*\) *(\{?|[^;])
Я думаю, что приведенное выше регулярное выражение может соответствовать почти всем возможным комбинациям объявлений методов Java, даже тем, которые включают в себя обобщения и массивы, являющиеся возвращаемыми аргументами, которым регулярное выражение, предоставленное оригинальным автором, не соответствовало.
Просмотрев другие ответы, вот к чему я пришел:
#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]*$
Где {#insert zJRgx123GenericsNotInGroup}
равно
`(?:<[?\w\[\] ,.&]+>)|(?:<[^<]*<[?\w\[\] ,.&]+>[^>]*>)|(?:<[^<]*<[^<]*<[?\w\[\] ,.&]+>[^>]*>[^>]*>)`
Ограничения:
- ЛЮБОЙ параметр может иметь многоточие:"..." (Java допускает только last)
- Максимум три уровня вложенных дженериков:(
<...<...<...>...>...>
ладно,<...<...<...<...>...>...>...>
плохой).Синтаксис внутри generics может быть очень фальшивым, и все же это регулярное выражение кажется приемлемым. - Не требует пробелов между типами и их (необязательными) открывающими дженериками '<'
- Распознает внутренние классы, но не запрещает использование двух точек рядом друг с другом, таких как Class ....InnerClass
Ниже приведен исходный код PhraseExpress (автоматический текст и описание в строке 1, основная часть в строке 2).Звонить {#insert zJRgxJavaFuncSigThrSemicOrOpnCrly}
, и ты получишь это:
^[ \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]*$
Необработанный код:
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
Мне также нужно было такое регулярное выражение, и я придумал это решение:
"((public|private|protected|static|final|native|synchronized|abstract|transient)+\\s)+[\\$_\\w\\<\\>\\[\\]]*\\s+[\\$_\\w]+\\([^\\)]*\\)?\\s*\\{?[^\\}]*\\}?"
Это грамматика и ответ Георгиоса Гусиоса были полезны для создания регулярного выражения.
Я почти уверен, что движок регулярных выражений Java по умолчанию является жадным, что означает, что "\w+ +\w+ *\(.*\) *\{"
никогда не будет совпадать, так как .*
внутри круглой скобки будет съедено все после открытия paren.Я рекомендую вам заменить .*
с помощью [^)], таким образом, вы выберете все символы, не являющиеся закрывающими парными.
ПРИМЕЧАНИЕ: Майк Стоун поправил меня в комментариях, и поскольку большинство людей на самом деле не открывают комментарии (я знаю, что часто их не замечаю):
Жадность не означает, что она никогда не совпадет...но он будет потреблять скобки, если после них будет больше скобок, чтобы удовлетворить остальную часть регулярного выражения...так, например, "public void foo(int arg) { if (test) { System.exit(0);} }" не будет соответствовать должным образом...
Я придумал вот что:
\b\w*\s*\w*\(.*?\)\s*\{[\x21-\x7E\s]*\}
Я протестировал это на PHP-функции, но она должна работать точно так же, это фрагмент кода, который я использовал:
function getProfilePic($url)
{
if(@open_image($url) !== FALSE)
{
@imagepng($image, 'images/profiles/' . $_SESSION['id'] . '.png');
@imagedestroy($image);
return TRUE;
}
else
{
return FALSE;
}
}
Подробная информация:
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
Чаевые:
Если вы собираетесь написать регулярное выражение на Perl, пожалуйста, используйте параметры "xms", чтобы вы могли оставить пробелы и задокументировать регулярное выражение.Например, вы можете написать регулярное выражение типа:
m{\w+ \s+ #return type
\w+ \s* #function name
[(] [^)]* [)] #params
\s* [{] #open paren
}xms
Один из вариантов (думаю, x) позволяет использовать # comments внутри регулярного выражения.Также используйте \s вместо " ".\s обозначает любой "пустой" символ.Таким образом, вкладки также будут совпадать - это то, чего вы хотели бы.В Perl вам не нужно использовать / /, вы можете использовать { } или < > или | |.
Не уверен, есть ли такая возможность у других языков.Если они это сделают, то, пожалуйста, используйте их.
(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]*) *\\{
Приведенное выше регулярное выражение обнаружит все возможные определения методов java.Протестировано на множестве файлов исходного кода.Чтобы также включить конструкторы, используйте приведенное ниже регулярное выражение :
(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]*) *\\{
При этом будет выбрано имя метода, а не вся строка целиком.
(?<=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+
Я создал регулярное выражение vim, чтобы сделать это для ctrlp/фанки основываясь на ответе Георгиоса Гусиоса.
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
Я бы предположил, что в Java это выглядит примерно так:
^\s+(?:<\w+>\s+){0,3}(?:[\w\<\>\[\]])+\s+\w+\s*\([^\)]*\)(?:\w|\s|\{)+$
Это для более конкретного варианта использования, но он намного проще, я считаю, им стоит поделиться.Я сделал это для поиска методов "public static void", т.е.Воспроизвести действия контроллера, и я сделал это из командной строки Windows / Cygwin, используя grep;видишь: https://stackoverflow.com/a/7167115/34806
cat Foobar.java | grep -Pzo '(?s)public static void.*?\)\s+{'
Последние две записи из моих выходных данных выглядят следующим образом:
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) {
Я нашел себа229ответ полезен, он отражает большинство сценариев, но не следующие,
public <T> T name(final Class<T> x, final T y)
Это регулярное выражение также зафиксирует это.
((public|private|protected|static|final|native|synchronized|abstract|transient)+\s)+[\$_\w\<\>\w\s\[\]]*\s+[\$_\w]+\([^\)]*\)?\s*
Надеюсь, это поможет.
(public|private|static|protected) ([A-Za-z0-9<>.]+) ([A-Za-z0-9]+)\(
Кроме того, вот последовательность замены, которую вы можете использовать в IntelliJ
$1 $2 $3(
Я использую его следующим образом:
$1 $2 aaa$3(
при преобразовании файлов Java в Kotlin необходимо предотвратить автоматическое превращение функций, начинающихся с "get", в переменные.Не работает с уровнем доступа "по умолчанию", но я сам им не часто пользуюсь.
Начиная с git 2.19.0, встроенное регулярное выражение для Java now, похоже, работает хорошо, так что в поставке вашего собственного, возможно, нет необходимости.
"!^[ \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]*\\([^;]*)$"
(Первая строка, по-видимому, предназначена для фильтрации строк, которые напоминают объявления методов, но таковыми не являются.)