gpt4 book ai didi

java - (?!a){0} 是什么?在 Java 正则表达式中是什么意思?

转载 作者:IT老高 更新时间:2023-10-28 21:09:10 27 4
gpt4 key购买 nike

灵感来自 question if {0} quantifier actually makes sense我开始使用一些包含 {0} 的正则表达式量词并编写了这个小型 java 程序,它只是根据各种测试正则表达式拆分测试短语:

private static final String TEST_STR =
"Just a test-phrase!! 1.2.3.. @ {(t·e·s·t)}";

private static void test(final String pattern) {
System.out.format("%-17s", "\"" + pattern + "\":");
System.out.println(Arrays.toString(TEST_STR.split(pattern)));
}

public static void main(String[] args) {
test("");
test("{0}");
test(".{0}");
test("([^.]{0})?+");
test("(?!a){0}");
test("(?!a).{0}");
test("(?!.{0}).{0}");
test(".{0}(?<!a)");
test(".{0}(?<!.{0})");
}

==> 输出:

"":              [, J, u, s, t,  , a,  , t, e, s, t, -, p, h, r, a, s, e, !, !,  , 1, ., 2, ., 3, ., .,  , @,  , {, (, t, ·, e, ·, s, ·, t, ), }]
"{0}": [, J, u, s, t, , a, , t, e, s, t, -, p, h, r, a, s, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }]
".{0}": [, J, u, s, t, , a, , t, e, s, t, -, p, h, r, a, s, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }]
"([^.]{0})?+": [, J, u, s, t, , a, , t, e, s, t, -, p, h, r, a, s, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }]
"(?!a){0}": [, J, u, s, t, , a, , t, e, s, t, -, p, h, r, a, s, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }]
"(?!a).{0}": [, J, u, s, t, a, , t, e, s, t, -, p, h, ra, s, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }]
"(?!.{0}).{0}": [Just a test-phrase!! 1.2.3.. @ {(t·e·s·t)}]
".{0}(?<!a)": [, J, u, s, t, , a , t, e, s, t, -, p, h, r, as, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }]
".{0}(?<!.{0})": [Just a test-phrase!! 1.2.3.. @ {(t·e·s·t)}]

以下内容并不让我感到惊讶:

  1. "" , ".{0}" , 和 "([^.]{0})?+"只是在每个字符之前拆分,这是有道理的,因为 0 量词。
  2. "(?!.{0}).{0}"".{0}(?<!.{0})"不匹配任何东西。对我来说很有意义:0-quantified token 的 Negative Lookahead/Lookbehind 不匹配。

让我感到惊讶:

  1. "{0}" & "(?!a){0}" :我实际上预计这里会出现异常,因为前面的标记无法量化:对于 {0} (?!a){0} 前面没有任何内容不仅仅是消极的前瞻性。两者都在每个字符之前匹配,为什么?如果我在 javascript validator 中尝试该正则表达式,我会得到“不可量化的错误”,see demo here !该正则表达式在 Java 和 Javascript 中的处理方式是否不同?
  2. "(?!a).{0}" & ".{0}(?<!a)" : 这里还有一个小惊喜:在短语的每个字符之前匹配,除了 a 之前/之后。 .我的理解是在 (?!a).{0} (?!a) Negative Lookahead 部分断言不可能匹配 a从字面上看,但我向前看.{0} .我认为它不适用于 0 量化标记,但看起来我也可以将 Lookahead 与这些标记一起使用。

==> 所以对我来说剩下的谜团是为什么(?!a){0}实际上在我的测试短语中的每个字符之前匹配。这不应该是一个无效的模式并抛出一个 PatternSyntaxException 或类似的东西吗?


更新:

如果我在一个 Android Activity 中运行相同的 Java 代码,结果会不同!有正则表达式 (?!a){0}确实会引发 PatternSyntaxException,请参阅:

03-20 22:43:31.941: D/AndroidRuntime(2799): Shutting down VM
03-20 22:43:31.950: E/AndroidRuntime(2799): FATAL EXCEPTION: main
03-20 22:43:31.950: E/AndroidRuntime(2799): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.appham.courseraapp1/com.appham.courseraapp1.MainActivity}: java.util.regex.PatternSyntaxException: Syntax error in regexp pattern near index 6:
03-20 22:43:31.950: E/AndroidRuntime(2799): (?!a){0}
03-20 22:43:31.950: E/AndroidRuntime(2799): ^
03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread.access$600(ActivityThread.java:141)
03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
03-20 22:43:31.950: E/AndroidRuntime(2799): at android.os.Handler.dispatchMessage(Handler.java:99)
03-20 22:43:31.950: E/AndroidRuntime(2799): at android.os.Looper.loop(Looper.java:137)
03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread.main(ActivityThread.java:5041)
03-20 22:43:31.950: E/AndroidRuntime(2799): at java.lang.reflect.Method.invokeNative(Native Method)
03-20 22:43:31.950: E/AndroidRuntime(2799): at java.lang.reflect.Method.invoke(Method.java:511)
03-20 22:43:31.950: E/AndroidRuntime(2799): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
03-20 22:43:31.950: E/AndroidRuntime(2799): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
03-20 22:43:31.950: E/AndroidRuntime(2799): at dalvik.system.NativeStart.main(Native Method)
03-20 22:43:31.950: E/AndroidRuntime(2799): Caused by: java.util.regex.PatternSyntaxException: Syntax error in regexp pattern near index 6:
03-20 22:43:31.950: E/AndroidRuntime(2799): (?!a){0}
03-20 22:43:31.950: E/AndroidRuntime(2799): ^
03-20 22:43:31.950: E/AndroidRuntime(2799): at java.util.regex.Pattern.compileImpl(Native Method)
03-20 22:43:31.950: E/AndroidRuntime(2799): at java.util.regex.Pattern.compile(Pattern.java:407)
03-20 22:43:31.950: E/AndroidRuntime(2799): at java.util.regex.Pattern.<init>(Pattern.java:390)
03-20 22:43:31.950: E/AndroidRuntime(2799): at java.util.regex.Pattern.compile(Pattern.java:381)
03-20 22:43:31.950: E/AndroidRuntime(2799): at java.lang.String.split(String.java:1832)
03-20 22:43:31.950: E/AndroidRuntime(2799): at java.lang.String.split(String.java:1813)
03-20 22:43:31.950: E/AndroidRuntime(2799): at com.appham.courseraapp1.MainActivity.onCreate(MainActivity.java:22)
03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.Activity.performCreate(Activity.java:5104)
03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
03-20 22:43:31.950: E/AndroidRuntime(2799): ... 11 more

为什么 Android 中的正则表达式的行为与普通 Java 不同?

最佳答案

我对 oracles java 1.7 的源做了一些调查。

"{0}"

我发现一些代码在主循环中找到 ?、* 或 + 时会抛出“悬空元字符”。也就是说,不是紧跟在一些文字、组、"." 之后。或任何其他明确检查量词的地方。出于某种原因,{不在该列表中。结果是它通过了对特殊字符的所有检查并开始解析文字字符串。它遇到的第一个字符是{ ,它告诉解析器是时候停止解析文字字符串并检查量词了。

结果是"{n}"将匹配空字符串 n 次。

另一个结果是第二个 "x{m}{n}"将首先匹配 x m次,然后匹配空字符串 n次,有效地忽略了 {n} ,正如@Kobi 在上面的评论中提到的那样。

对我来说似乎是一个错误,但如果他们想保留它以实现向后兼容性,我不会感到惊讶。

"(?!a){0}"

"(?!a)"只是一个可量化的节点。您可以检查下一个字符是否为 'a' 10 次。但是每次都会返回相同的结果,所以它不是很有用。在我们的例子中,它将检查下一个字符是否为 'a' 0 次,这将始终成功。

请注意,当匹配长度为 0 时(例如此处),作为一种优化,量词永远不会贪婪。这也防止了 "(?!a)*" 中的无限递归。案例。

"(?!a).{0}" & ".{0}(?<!a)"

如上所述,{0}执行检查 0 次,始终成功。它有效地忽略了它之前的任何东西。这意味着 "(?!a).{0}""(?!a)" 相同,有预期的结果。

另一个类似。

Android 与众不同

正如@GenericJam 所提到的,android 是一种不同的实现,在这些边缘情况下可能具有不同的特征。我也尝试查看该源代码,但 android 实际上在那里使用 native 代码:)

关于java - (?!a){0} 是什么?在 Java 正则表达式中是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22182007/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com