举个例子。
public static FieldsConfig getFieldsConfig(){
if(xxx) {
sssss;
}
return;
}
我写了一个正则表达式,"\\s*public\\s*static.*getFieldsConfig\\(.*\\)\\s*\\{"
它只能匹配第一行。但是如何正确匹配最后的"}"方法?
帮帮我。感谢。
编辑: 未指定方法{}的内容。但模式肯定是这样的,
public static xxx theKnownMethodName(xxxx) {
xxxxxxx
}
答案 0 :(得分:3)
我决定更进一步;)
这是一个正则表达式,它将为您提供不同捕获组中函数的修饰符,类型,名称和正文:
((?:(?:public|private|protected|static|final|abstract|synchronized|volatile)\s+)*)
\s*(\w+)\s*(\w+)\(.*?\)\s*({(?:{[^{}]*}|.)*?})
它处理嵌套大括号(@callOfCode (半)可能使用正则表达式;)和一组固定的修饰符。
它不处理复杂的东西,如评论中的大括号和类似的东西,但它适用于最简单的。
此致
编辑:并回答你的问题;),你感兴趣的是捕获组4。
编辑2:正如我所说 - 简单。但是你可以使处理更复杂的方法变得更复杂。 Here's an updated handling one more level of nesting
((?:(?:public|private|protected|static|final|abstract|synchronized|volatile)\s+)*)
\s*(\w+)\s*(\w+)\(.*?\)\s*({(?:{[^{}]*(?:{[^{}]*}|.)*?[^{}]*}|.)*?})
你可以在另一个层面...而另一个......但是正如有人评论 - 这不应该由正则表达式完成。然而,这会处理简单方法。
答案 1 :(得分:2)
正则表达式绝对不是最好的工具,但如果你想要正则表达式,并且你的代码缩进,你可以试试:
^(?<indent>\s*)(?<mod1>\w+)\s(?<mod2>\w+)?\s*(?<mod3>\w+)?\s*(?<return>\b\w+)\s(?<name>\w+)\((?<arg>.*?)\)\s*\{(?<body>.+?)^\k<indent>\}
它有其他命名组,您可以删除它们。它使用缩进级别来查找最后}
。
答案 2 :(得分:1)
您需要启用DOTALL模式。然后dot将匹配newLine字符。只需在正则表达式的开头添加(?s)
。
String s = " public static FieldsConfig getFieldsConfig(){\n"
+ " if(xxx) {\n"
+ " sssss;\n"
+ " }\n"
+ " return;\n"
+"}";
Matcher m = Pattern.compile("(?s)\\s*public\\s+static\\s+\\w+?\\sgetFieldsConfig\\(\\s*\\).*").matcher(s);
m.find();
System.out.println(m.group());
Outpup是你想要的所有方法体。没有(?s)
,它只匹配第一行。但你不能用正则表达式解析java代码。其他人已经说过了。此正则表达式将匹配从方法签名开始到文件结尾的所有内容。如何匹配才能到达方法体的末尾?方法可以包含许多{....}
以及许多return;
。正则表达式不是一个魔术棒。
答案 3 :(得分:1)
试试这个
((?<space>\h+)public\s+static\s+[^(]+\([^)]*?\)\s*\{.*?\k<space>\})|(public\s+static\s+[^(]+\([^)]*?\)\s*\{.*?\n\})
<强>解释强>:
我们将按关键字public
结束}
结束方法块开始,public
和}
必须具有相同的\s
字符,因此您的代码必须格式正确: )https://en.wikipedia.org/wiki/Indent_style
\h
:匹配空格但不匹配换行符
(?<space>\h+)
:在public
之前获取所有空格,然后在space
名称中分组
public\s+static\s
公共静态
[^(]
:任何字符,但不是(
([^)]
:任何但不是)
\k<space>\}
:}
结束number of whitespace
,然后}
。
输入:
public static FieldsConfig getFieldsConfig(){
if(xxx) {
sssss;
}
return;
}
NO CAPTURE
public static FieldsConfig getFieldsConfig2(){
if(xxx) {
sssss;
}
return;
}
NO CAPTURE
public static FieldsConfig getFieldsConfig3(){
if(xxx) {
sssss;
}
return;
}
NO CAPTURE
public static FieldsConfig getFieldsConfig4(){
if(xxx) {
sssss;
}
return;
}
输出:
MATCH 1
3. [0-91] `public static FieldsConfig getFieldsConfig(){
if(xxx) {
sssss;
}
return;
}`
MATCH 2
3. [105-197] `public static FieldsConfig getFieldsConfig2(){
if(xxx) {
sssss;
}
return;
}`
MATCH 3
1. [211-309] ` public static FieldsConfig getFieldsConfig3(){
if(xxx) {
sssss;
}
return;
}`
MATCH 4
1. [324-428] ` public static FieldsConfig getFieldsConfig4(){
if(xxx) {
sssss;
}
return;
}`
答案 4 :(得分:1)
谢谢大家。经过一番考虑后,我在某种程度上找到了可靠的方法。现在分享。
String regex ="\\s*public\s+static\s+[\w\.\<\>,\s]+\s+getFieldsConfig\\(.*?\\)\\s*\\{.*?\\}(?=\\s*(public|private|protected|static))";
String regex2 = "\\s*public\s+static\s+[\w\.\<\>,\s]+\s+getFieldsConfig\\(.*?\\)\\s*\\{.*?\\}(?=(\\s*}\\s*$))";
regex = "(" + regex +")|("+ regex2 + "){1}?";
Pattern pattern = Pattern.compile(regex, Pattern.DOTALL)
它可以很好地匹配我的方法体。
PS 是的,正则表达式可能不是非常严格地解析方法的合适方法。一般来说,正则表达式比编程更省力,在特定情况下工作正常。调整它,确保它适合你。
答案 5 :(得分:1)
维克多,你已经让我推荐你的答案了。所以我决定花点时间写一篇完整的评论并给出一些提示。我不是某种正则表达式专业人士,也不是非常喜欢它。目前我正在开发一个大量使用正则表达式的项目,所以我已经看到并写了它的内容,可以非常可靠地回答你的问题并且厌倦了正则表达式。 所以,让我们开始你的正则表达式分析:
String regex ="\\s*public\\s*static.*getFieldsConfig\\(.*?\\)\\s*\\{.*\\}(?=\\s*(public|private|protected|static))";
String regex2 = "\\s*public\\s*static.*getFieldsConfig\\(.*?\\)\\s*\\{.*\\}(?=(\\s*}\\s*$))";
regex = "(" + regex +")|("+ regex2 + "){1}?";
我看到你为了便于阅读而制作了三个部分。这是一个好主意。我将从第一部分开始:
\\s\*public\\s\*static.*getFieldsConfig
您允许任意数字,包括public
和static
之间的零空格。它可以匹配publicstatic。每次在必须与部分数量的空格分隔的单词之间使用\\s+
。(.\*?\\)\\s\*\\{.\*\\}
您允许在第一批之间出现任何内容。它将匹配任何符号,直到)
。现在我们达到了使你的正则表达式工作的部分不像你想要的那样。 \\{.*\\}
是一个重大错误。它会匹配所有内容 }
最后一个文件 public
private
protected
{{1} } 到达了。我已将您的static
方法粘贴到java文件并进行了测试。仅使用正则表达式的第一部分(getFieldsConfig
)来处理从方法到文件中的最后一个方法的所有内容。没有必要逐步分析其他部分,因为"\\s*public\\s*static.*getFieldsConfig\\(.*?\\)\\s*\\{.*\\}(?=\\s*(public|private|protected|static))"
会破坏一切。在第二部分(\\{.*\\}
)中,您已经从方法到文件中的最后regex2
进行了匹配。您是否尝试打印正则表达式匹配的内容?试试吧:
}
简短的代码片段,展示您的正则表达式的工作原理。如果需要,处理异常。只需将package com.tryRegex;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TryRegex{
public static void main(String[] args) throws IOException{
File yourFile = new File("tryFile.java");
Scanner scanner = new Scanner(yourFile, "UTF-8");
String text = scanner.useDelimiter("\\A").next(); // `\\A` marks beginning of file. Since file has only one beginning, it will scan file from start to beginning.
String regex ="\\s*public\\s*static.*getFieldsConfig\\(.*?\\)\\s*\\{.*\\}(?=\\s*(public|private|protected|static))";
String regex2 = "\\s*public\\s*static.*getFieldsConfig\\(.*?\\)\\s*\\{.*\\}(?=(\\s*}\\s*$))";
regex = "(?s)(" + regex +")|("+ regex2 + "){1}?"; // I've included (?s) since we reading from file newline chars are not excluded. Without (?s) it would match anything unless your method is written in a single line.
Matcher m = Pattern.compile(regex).matcher(text);
System.out.println(m.find() ? m.group() : "No Match found");
}
}
放到项目文件夹中即可运行。
现在我将向您展示实际上有多乱的正则表达式:
yourFile.java
基本上这个正则表达式匹配每个方法。但它也有缺陷。我将探讨它以及它的缺陷。
String methodSignature = "(\\s*((public|private|protected|static|final|abstract|synchronized|volatile)\\s+)*[\\w<>\\[\\]\\.]+\\s+\\w+\\s*\\((\\s*[\\w<>\\[\\]\\.]*\\s+\\w+\\s*,?)*\\s*\\))";
String regex = "(?s)" + methodSignature + ".*?(?="+ methodSignature + ")";
任何时候都匹配任何指定的修饰符(和至少一个空格),包括零,因为方法可以没有修饰符。 (为了简单起见,我留下了许多修饰符允许无限制。在真正的解析器中,我不会允许这样做,也不会使用正则表达式执行此类任务。)\\s*((public|private|protected|static|final|abstract|synchronized|volatile)\\s+)*
这是方法的返回类型。它可以包含单词字符,[\\w<>\\[\\]\\.]+
表示泛型类型,<>
表示数组,[]
表示嵌套类表示法。.
方法的名称。\\s+\\w+\\s*\\
特别棘手的部分 - 方法参数。首先,您可以认为可以使用\\((\\s*[\\w<>\\[\\]\\.]*\\s+\\w+\\s*,?)*\\s*\\))
轻松替换此部分。我也这么认为。但后来我注意到它不仅匹配方法,而且还匹配匿名类,如(
最简单,最有效的方法是避免这种情况,方法是指定方法参数结构。 new Anonymous(someVariable){....}
是可以构成参数类型的可能符号。 [\\w<>\\[\\]\\.]
参数类型后跟至少一个空格和参数名称。如果method包含多个参数,则参数名称后跟\\s+\\w+\\s*,?
。那么关于缺陷的是什么?主要缺陷是方法中定义的类。方法可以在其中包含类定义。考虑一下这种情况:
,
这很好地解释了为什么正则表达式不适合这样的工作。无法从java文件可靠地解析方法,因为方法可能是嵌套结构。方法可以包含类定义,这些类可以包含具有其他类定义的方法,依此类推。正则表达式被无限递归捕获并失败。
另一个案例是正则表达式会失败是评论。在评论中,您可以输入任何内容
public void regexIsAGoodThing(){
//some code
new RegexIsNotSoGoodActually(){
void dissapontingMethod(){
//Efforts put in writing this regex was pointless because of this dissapointing method.
}
}
}
我们不能忘记的另一件事是注释。如果下一个方法被注释怎么办?那个正则表达式几乎可以匹配,除了它也会匹配注释。这可以避免,但正则表达式将更大。
void happyRegexing(){
return void;
// public void happyRegexingIsOver(){....}
}
另一个案例是块。如果两个方法之间包含静态或实例块会怎么样?
public void goodDay(){
}
@Zzzzz //This annotation can be carried out by making our regex even more larger
public void goodNight(){
}
P.S 它有另一个缺陷 - 它匹配public void iWillNotDoThisAnyMore(){
}
static{
//some code
}
public void iWillNotParseCodeWithRegex(){
//end of story
}
以及下一个方法签名之前的所有内容。你可以解决这个问题,但是再一次 - 这可以解决,但不是优雅的代码。我还没有包含文件匹配的结尾。如果您有兴趣,也许我明天会添加编辑。现在去睡觉,它在欧洲接近早晨。
正如您所看到的,正则表达式是几乎大多数任务的好工具。但我们程序员讨厌几乎。我们的词汇表中甚至没有它。我们不是吗?
答案 6 :(得分:0)
我必须根据自己的需要修改此答案。我想要整个方法的捕获组以及文件中每个方法的名称。我只需要这两个捕获组。这需要PCRE中的单行标志。在其他REGEX解析中,将需要全局(g)标志来捕获完整文件,而不仅仅是一个匹配。我嵌套了括号捕获@SamWhan,显示允许五个级别的嵌套。这应该可以完成工作,因为更多工作违反了大多数推荐标准。因此,此REGEX确实非常昂贵,因此请注意。
(?:public|private|protected|static|final|abstract|synchronized|volatile)\s*(?:(?:(?:\w*\s)?(\w+))|)\(.*?\)\s*(?:\{(?:\{[^{}]*(?:\{[^{}]*(?:\{[^{}]*(?:\{[^{}]*(?:\{[^{}]*(?:\{[^{}]*}|.)*?[^{}]*}|.)*?[^{}]*}|.)*?[^{}]*}|.)*?[^{}]*}|.)*?[^{}]*}|.)*?})