StackTraceElement
的字符串形式。 (请注意,这不是堆栈跟踪本身的正则表达式。)典型形式如StackTraceElement.toString()
所示:
- 请参阅下面的描述 [在 API 文档中]。"com.foo.loader/[email protected]/com.foo.Main.run(Main.java:101)"
- 行号不可用。"com.foo.loader/[email protected]/com.foo.Main.run(Main.java)"
- 文件名和行号都不可用。"com.foo.loader/[email protected]/com.foo.Main.run(Unknown Source)"
- 包含执行点的方法是本机方法。"com.foo.loader/[email protected]/com.foo.Main.run(Native Method)"
- 执行点的类定义在名为"com.foo.loader//com.foo.bar.App.run(App.java:12)"
的类加载器的未命名模块中。com.foo.loader
- 执行点的类定义在由内置类加载器(例如应用程序类加载器)加载的"[email protected]/org.acme.Lib.test(Lib.java:80)"
模块中。acme
-"MyClass.mash(MyClass.java:9)"
类位于应用程序类路径上。MyClass
我需要能够在结果匹配器中将每个组件作为一个组进行访问。
目前我有以下正则表达式(为了可读性,未对 Java 字符串进行转义):
(?:([^@/]+)/)?(?:(?:([^@/]+)@([\d.+-]+))?/)?([^(]+)\.([^.(]+)\(([^:)]+)(?::(\d+))??\)
或者用Java代码:
public static final Pattern ELEMENT_PATTERN = Pattern.compile("(?:([^@/]+)/)?"
+ "(?:(?:([^@/]+)@([\\d.+-]+))?/)?" //optional module name/module version, followed by slash
+ "([^(]+)" //declaring class is always required
+ "\\.([^.(]+)" //method name is always required
+ "\\(([^:)]+)(?::(\\d+))??\\)"); //"file name" (always present in some form, but not necessarily the actual filename) and optional line number
有两个小缺点。这些并不是什么大问题,但解决它们会很好。
"/com.foo.bar.App.run(App.java:12)"
,我认为应该禁止它。允许“前两个组件中的一个或两个,但如果其中一个存在,则仅在尾随斜杠”似乎有点复杂。([^(]+)
和\.([^.(]+)
部分需要回溯,因为第一部分首先会消耗方法名称。我怀疑这效率太低了,但如果有更好的方法,我不会感到惊讶。我想出的正则表达式可能足以满足我的目的,但是正则表达式专家知道如何解决我提到的这两个问题吗?
这就是我的想法。我所做的最重要的调整是模块版本不必是数字。事实上,规范并不以任何方式限制字符,包括斜杠的使用。我尝试为模块分配一个带有
/
的版本,并且它被接受了。
private static final String ID =
"\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*";
private static final String NAME = ID + "(?:\\." + ID + ")*";
private static final String MODULE = "(" + NAME + ")(?:@(.+))?/";
/**
* Groups:
* <ul>
* <li>1: classloader name
* <li>2: module name, if loaded from custom classloader
* <li>3: module version, if loaded from custom classloader
* <li>4: module name, if NOT loaded from custom classloader
* <li>5: module version, if NOT loaded from custom classloader
* <li>6: class name
* <li>7: method name
* <li>8: source file
* <li>9: line number
* <li>10: text when line number unknown
* </ul>
*
* Only class name and method name are guaranteed to be present;
* everything else is optional.
*/
private static final Pattern STACK_TRACE_ELEMENT_PATTERN = Pattern.compile(
"\\bat\\s+"
+ "(?:(" + NAME + ")/(?:/|" + MODULE + ")|" + MODULE + ")?"
+ "(" + NAME + ")\\.(" + ID + ")\\((?:"
+ "(" + ID + "\\.java)(?::(\\d+))?"
+ "|([^)]*)"
+ ")\\)");