调整 Java 堆栈跟踪元素的正则表达式

问题描述 投票:0回答:1

我正在创建一个 Java 正则表达式来匹配 Java

StackTraceElement
的字符串形式。 (请注意,这不是堆栈跟踪本身的正则表达式。)典型形式如
StackTraceElement.toString()
所示:

  • "com.foo.loader/[email protected]/com.foo.Main.run(Main.java:101)"
    - 请参阅下面的描述 [在 API 文档中]。
  • "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

有两个小缺点。这些并不是什么大问题,但解决它们会很好。

  1. 这个正则表达式将允许
    "/com.foo.bar.App.run(App.java:12)"
    ,我认为应该禁止它。允许“前两个组件中的一个或两个,但如果其中一个存在,则仅在尾随斜杠”似乎有点复杂。
  2. 我相信
    ([^(]+)
    \.([^.(]+)
    部分需要回溯,因为第一部分首先会消耗方法名称。我怀疑这效率太低了,但如果有更好的方法,我不会感到惊讶。

我想出的正则表达式可能足以满足我的目的,但是正则表达式专家知道如何解决我提到的这两个问题吗?

java regex stack-trace
1个回答
0
投票

这就是我的想法。我所做的最重要的调整是模块版本不必是数字。事实上,规范并不以任何方式限制字符,包括斜杠的使用。我尝试为模块分配一个带有

/
的版本,并且它被接受了。

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+))?"
        + "|([^)]*)"
        + ")\\)");
© www.soinside.com 2019 - 2024. All rights reserved.