我正在浏览Java Tutorial on Quantifiers。
贪婪,不情愿和占有量词之间的差异有所不同。
我无法完全理解其中的区别。
解释如下:
Enter your regex: .*foo // greedy quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfooxxxxxxfoo" starting at index 0 and ending at index 13.
Enter your regex: .*?foo // reluctant quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfoo" starting at index 0 and ending at index 4.
I found the text "xxxxxxfoo" starting at index 4 and ending at index 13.
Enter your regex: .*+foo // possessive quantifier
Enter input string to search: xfooxxxxxxfoo
No match found.
第一个例子使用贪婪量词。*来找到"任何",零次或多次,然后是字母" f" " O" " O&#34 ;.因为量词是贪婪的,所以表达式的。*部分首先会占用整个输入字符串。此时,整体表达式不能成功,因为已经消耗了最后三个字母(" f"" o"" o")。因此,匹配器一次缓慢地退回一个字母,直到最右边出现" foo"已经反刍,此时比赛成功,搜索结束。
然而,第二个例子是不情愿的,所以它首先消费"没什么"。因为" foo"没有出现在字符串的开头,它被迫吞下第一个字母(" x"),这会触发第一个匹配0和4.我们的测试工具继续直到输入字符串用尽的过程。它在4和13找到另一场比赛。
第三个例子找不到匹配,因为量词是占有性的。在这种情况下,整个输入字符串被。* +消耗,不留任何东西来满足" foo"在表达的最后。使用占有量词来表示你想要抓住所有东西而不会退缩的情况;在没有立即找到匹配的情况下,它将胜过等效的贪心量词。
答案 0 :(得分:10)
懒惰(不情愿)&的主要区别贪婪的情况是,回溯结构的行为,以及所有格的情况也是如此激进!
f
的匹配,所以每当你有一个foo
短语时,你就会得到一个匹配,这就是为什么我们从它的用法中得到多个匹配。*?foo
的 X 强> fooxxxxxxfoo
在开始时,懒惰的情况将与x
成功匹配(在成功的空匹配之后)并将焦点传递给下一个运算符;foo
正则表达式的x
部分,因为它出现在foo
之后,我们得到了这个片段的匹配,对于字符串的次要部分也是一样的。
。* foo
xfooxxxxxxfo的 0 强>
当贪婪的情况在此时(最后一个字符)时,匹配将失败,因为我们无法匹配正则表达式的backtrace
部分。比回溯将迫使贪婪的案件foo
执行其步骤并强制执行下一个操作员foo
,类似于懒惰案件;
xfooxxxxxx的 ˚F 强> OO
此时,backtracking
部分将获得成功匹配,从而以整个字符串的成功匹配结束。
backtrack
的匹配失败的最后一部分,这不是占有的情况。如果它可以匹配,它将拥有并将在此过程中牺牲比赛的成功。如果它在匹配字符时失败,那么焦点就会传递给正则表达式的下一个运算符。。* + foo
xfooxxxxxxfo的 0 强>
类似于贪婪的情况,我们已到达字符串的末尾,但是占有情况仍然可以匹配它,因此不会将火炬传递给<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_aplication_settings" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#e2e2e2" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.smok.maps.AplicationSettings"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true"> <TextView android:id="@+id/textSync" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#000000" android:text="@string/sync" /> <LinearLayout android:id="@+id/line1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/textSync"> <TextView android:id="@+id/actual" android:layout_width="wrap_content" android:textColor="#000000" android:layout_height="wrap_content" android:text="@string/actual" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/count" /> <TextView android:id="@+id/actual2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#000000" android:text="min" /> </LinearLayout> <LinearLayout android:id="@+id/lin2" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/line1" android:orientation="horizontal"> <CheckBox android:id="@+id/checkBox1" android:layout_width="50dp" android:layout_height="50dp" android:button="@xml/setting_checkbox" android:focusable="false" android:gravity="center" /> <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" android:src="@drawable/point" /> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:textColor="#000000" android:text="@string/show_choose_point" /> </LinearLayout> <LinearLayout android:id="@+id/lin3" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/lin2" android:orientation="horizontal"> <CheckBox android:id="@+id/checkBox2" android:layout_width="50dp" android:layout_height="50dp" android:button="@xml/setting_checkbox" android:focusable="false" android:gravity="center" /> <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" android:src="@drawable/sync" /> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:textColor="#000000" android:gravity="center" android:text="@string/sync_request" /> </LinearLayout> <LinearLayout android:id="@+id/lin4" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/lin3" android:orientation="horizontal"> <CheckBox android:id="@+id/checkBox3" android:layout_width="50dp" android:layout_height="50dp" android:button="@xml/setting_checkbox" android:focusable="false" android:gravity="center" /> <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" android:src="@drawable/show_chooce" /> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:textColor="#000000" android:gravity="center" android:text="@string/show_choosen_points" /> </LinearLayout> <LinearLayout android:id="@+id/lin5" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/lin4" android:orientation="horizontal"> <CheckBox android:id="@+id/checkBox4" android:layout_width="50dp" android:layout_height="50dp" android:button="@xml/setting_checkbox" android:focusable="false" android:gravity="center" /> <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" android:src="@drawable/position2" /> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:textColor="#000000" android:text="@string/current_location" /> </LinearLayout> </RelativeLayout> <LinearLayout android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:orientation="horizontal"> <Button android:id="@+id/back_bt" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:textColor="#ffffff" android:background="@xml/roundedbutton" android:text="@string/back" /> <View android:layout_width="0dp" android:layout_weight="0.1" android:layout_height="match_parent"> </View> <Button android:id="@+id/confirm_bt" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:textColor="#ffffff" android:background="@xml/roundedbutton" android:text="@string/save" /> </LinearLayout> </RelativeLayout>
结构,并且会导致匹配失败。 / p>
答案 1 :(得分:7)
理解量词?
,*
和+
(分别为“零或一”,“零或更多”,“一个或多个”)的基本知识
只有了解正则表达式解析器的工作方式时,才能理解“回溯”的含义(参见下面的“动态示例”)。
?
:先测试1次,然后是0;如果你发现了1次,那么你需要丢弃它,你可以这样做??
:首先测试0次,然后测试1次?+
:先测试1次,然后是0;如果你发现了一次,然后你需要丢弃它,你不能这样做*
:尝试尽可能多地出现(甚至为0);如果你发现N次出现然后你需要丢弃(部分)它们,你可以从最后一次开始*?
:尝试尽可能减少出现次数(即使为0)*+
:尝试尽可能多地出现(甚至为0);如果您发现了N次,然后您需要丢弃(部分)它们,那么不能这样做+
:尝试尽可能多地出现(至少1次);如果你发现N次出现然后你需要丢弃(部分)它们,你可以从最后一次开始+?
:尝试减少发生次数(至少1次)++
:尝试尽可能多地出现(至少1次);如果您发现了N次,然后您需要丢弃(部分)它们,那么不能这样做在本节中,我将尝试向您展示正则表达式解析器背后的逻辑:
1)案例/.*foo/
:
首先是转向子模式/.*/
。它开始详细说明第一个字符:
xfooxxxxxxfoo
^
然后它试图详细说明尽可能多的字符:
xfooxxxxxxfoo
^^
xfooxxxxxxfoo
^^^
[...]
xfooxxxxxxfoo
^^^^^^^^^^^
xfooxxxxxxfoo
^^^^^^^^^^^^
xfooxxxxxxfoo
^^^^^^^^^^^^^
光标到达结尾,但子模式/foo/
尚未发挥作用。因此,光标“返回”以允许子模式/foo/
获得匹配:
xfooxxxxxxfoo
^^^^^^^^^^^^
/foo/
仍无法获得匹配,因此我们需要再次返回:
xfooxxxxxxfoo
^^^^^^^^^^^
xfooxxxxxxfoo
^^^^^^^^^^
现在子模式/foo/
可以匹配:
xfooxxxxxxfoo
^^^^^^^^^^^^^
所以匹配是整个字符串xfooxxxxxxfoo
。
2)案例/.*?foo/
:
首先是转向子模式/.*?/
。它是懒惰的,所以我们喜欢它匹配0个字符。但如果确实如此,子模式/foo/
无法获得匹配,因此必须详细说明一个字符:
xfooxxxxxxfoo
^
现在轮到foo
了:
xfooxxxxxxfoo
^^^^
所以匹配为xfoo
。
(如果为正则表达式设置类型global
,那么解析器将从匹配后的第一个字符重新启动,给出第二个匹配xxxxxxfoo
)
3)案例/.*+foo/
:
首先是转向子模式/.*+/
。它试图详细说明尽可能多的字符:
xfooxxxxxxfoo
^
[...]
xfooxxxxxxfoo
^^^^^^^^^^^^^
光标到达结尾,但子模式/foo/
尚未发挥作用。所以光标“回头”......哦不,多么可惜,它不能(因为它占有欲)!
所以我们没有比赛。