Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
负环视正则表达式-仅出现一次-Java_Java_Regex_String Matching - Fatal编程技术网

负环视正则表达式-仅出现一次-Java

负环视正则表达式-仅出现一次-Java,java,regex,string-matching,Java,Regex,String Matching,我试图找出一个字符串是否只包含一个单词的出现处 e、 g 字符串中的任何位置都可能出现多个foo,因此它们可以是非连续的 我使用字符串foobarfoo在java中测试以下正则表达式匹配,但它不起作用,并且返回true: static boolean testRegEx(String str){ return str.matches(".*(foo)(?!.*foo).*"); } 我知道这个主题看起来可能重复,但我很惊讶,因为当我使用这个正则表达式时:(foo)(?!*foo)。*它

我试图找出一个字符串是否只包含一个单词的出现处

e、 g

字符串中的任何位置都可能出现多个
foo
,因此它们可以是非连续的

我使用字符串
foobarfoo
在java中测试以下正则表达式匹配,但它不起作用,并且返回true

static boolean testRegEx(String str){
    return str.matches(".*(foo)(?!.*foo).*");
}
我知道这个主题看起来可能重复,但我很惊讶,因为当我使用这个正则表达式时:
(foo)(?!*foo)。*
它可以工作


知道为什么会这样吗

您可以使用此模式:

^(?>[^f]++|f(?!oo))*foo(?>[^f]++|f(?!oo))*$
它有点长,但性能很好

与ashdflasd字符串的经典示例相同:

详情:

(?>               # open an atomic group
    [^f]++        # all characters but f, one or more times (possessive)
  |               # OR
    f(?!oo)       # f not followed by oo
)*                # close the group, zero or more times
++
就像贪婪的量词
++
,但不允许回溯

(?>…)
类似于非捕获组
(?:…)
,但也不允许回溯

这些功能用于性能(内存和速度),但子模式可替换为:

(?:[^f]+|f(?!oo))*

如果您想检查一个字符串是否包含另一个字符串,这里有两个可能的解决方案(一个带regex,一个不带regex)

它们都很好用。下面是您的示例演示:

    String str1 = "jjdhfoobarfoo";
    String str2 = "wewwfobarfoo";
    String str3 = "jjfffoobarfo";
    String foo = "foo";
    System.out.println(containsOnlyOnce(str1, foo)); // false
    System.out.println(containsOnlyOnce(str2, foo)); // true
    System.out.println(containsOnlyOnce(str3, foo)); // true
    System.out.println(containsRegexOnlyOnce(str1, foo)); // false
    System.out.println(containsRegexOnlyOnce(str2, foo)); // true
    System.out.println(containsRegexOnlyOnce(str3, foo)); // true

有人回答了问题,但删除了它

以下短代码工作正常:

static boolean testRegEx(String str){
    return !str.matches("(.*?foo.*){0}|(.*?foo.*){2,}");
}

你知道如何在正则表达式内部反转结果吗

正则表达式的问题是,第一个
*
最初消耗整个字符串,然后后退,直到找到一个与其余正则表达式匹配的位置。这意味着,如果字符串中有多个
foo
,您的正则表达式将始终与最后一个匹配。从这一立场出发,前瞻也将永远成功

用于验证的正则表达式必须比用于匹配的正则表达式更精确。您的正则表达式失败,因为
*
可以匹配哨兵字符串“foo”。您需要在尝试匹配的
foo
之前和之后主动阻止匹配。展示了一种方法;还有一个:

"^(?>(?!foo).)*+foo(?>(?!foo).)*+$"
虽然效率不高,但我认为它更容易阅读。事实上,您可能会使用以下正则表达式:

"^(?!.*foo.*foo).+$"
它的效率要低得多,但是一个完整的regexn00b可能会知道它的功能


最后,请注意,这些正则表达式——我的或Casimir的——都没有使用lookbehind。我知道这似乎是做这项工作的完美工具,但事实上,回头看永远不应该是你想要的第一个工具。而且不仅仅是在Java中。无论您使用什么regex风格,以正常方式匹配整个字符串几乎总是比使用lookbehinds更容易。而且通常效率也更高。

使用两个固定式外观头:

static boolean testRegEx(String str){
    return str.matches("^(?=.*foo)(?!.*foo.*foo.*$).*");
}

有两个关键点是,有一个消极的前瞻性检查,检查是否有2个foo's锚定到start,并且重要的是包含输入结束。

第二个正则表达式与第一个输入字符串匹配,这就是所发生的情况。虽然,对于第二个输入示例,它将返回
false
。但通常字符串可能不会以
foo
开头。现在问题已编辑,
foo
可能发生在字符串中的任何位置,而另一个
foo
则是Too。因此,您的意思是,对于更长的模式,没有通用的方法?就像对于
LJKASHDFLASDFKJHASDFLKJHASDLKJHASDLKJHASDLFJK
你不能做同样的事情,对吗?请注意,
foo
只是一个例子here@ArianHosseinzadeh:您可以使用所需的字符串执行此操作。您所需要的只是拆分第一个字母上的字符串以动态组合您的模式。请您详细说明一下
++
是什么?你为什么不在任何地方使用“.*”?这个
{0}
是干什么的?如果你这么想的话,它不会阻止与
foo
匹配。事实上,它基本上把第一个替代方案变成了一个不可操作的选项。
{0}
有合法的用途,但这不是其中之一。至于反转正则表达式,您可以将其包装为一个负的前瞻,但我不建议这样做:
^(?!(?:(.*foo.*){0}|(.*foo.*){2,})$。+$
"^(?>(?!foo).)*+foo(?>(?!foo).)*+$"
"^(?!.*foo.*foo).+$"
static boolean testRegEx(String str){
    return str.matches("^(?=.*foo)(?!.*foo.*foo.*$).*");
}