是什么意思(?!^)

我正在尝试学习正则表达式并感到困惑。 我看到了这篇文章的java split()方法
所以我对Achintya Jha的第二个答案有些疑问;

  1. 为什么str2.split(""); 给出[, 1, 2, 3]
  2. 它是否在文本开头检测到"" ,如果是,为什么它最后不会这样做?
  3. 究竟是什么(?!^)意思?

如果我没有错a(?!b)返回a如果a后面没有b
^找到必须在行开头匹配的正则表达式,因此(?!^)获取一个空字符串""
^找到必须在该行的开头匹配的""如果此""后面没有""则返回""

拆分发生在匹配作为参数传递的正则表达式的地方。 你需要知道,如果分裂发生,一件事就变成了两件事。 总是。 没有例外。

您可以怀疑它,因为实例"abc".split("c")返回带有一个元素["ab"]数组,但这是因为此版本的split在返回之前还会自动从数组中删除尾随空字符串。

换句话说"abc".split("c")

  1. 创建["ab",""]数组(是的,有空字符串,这是c上拆分"abc"结果),
  2. 删除尾随空字符串
  3. 返回结果数组,结尾没有那些空字符串,所以现在返回["ab"]

另一个例子是在"a"上拆分"abc" "a" 。 由于a在开始时出现,你将获得["", "bc"]

但是拆分空字符串有点棘手,因为空字符串在每个字符之前和之后。 我将用管道标记它们 。

所以"abc"空字符串可以在这些位置找到"|a|b|c|" 这意味着当你在""上拆分"abc"

  • 这个方法(首先)产生数组["", "a", "b", "c", ""]
  • 然后删除尾随的空字符串

这就是为什么"abc".split("")返回结果数组["", "a", "b", "c"] (这应该回答你的问题1)。

但是如果我们想要防止第一个空字符串(开始时的那个)被split方法匹配呢? 换句话说,如果我们不想拆分怎么办?

 "|a|b|c|" 

但只有

  "a|b|c|" 

我们可以通过几种方式做到这一点。

  1. 我们可以尝试创建正则表达式,它将匹配这些具有任何字符的whatspace,就像a| b| c|
  2. 我们还可以说我们想要拆分在它们之前没有字符串开头的whatspace。

要创建这样的正则表达式,我们需要环视机制。

    • 说空Stirng只是用""
    • 要说某些东西需要在它之前有其他东西我们可以使用正面观察(?<=.)

    如果我们将前两个品脱结合起来: "(?<=.)"""我们将得到"(?<=.)"+""这就是"(?<=.)"所以"abc".split("(?<=.)")应仅在这些前面带有任何字符的空字符串上拆分(在由dot表示的正则表达式中)。

  1. 要说某些东西不能停留在字符串的开头,我们可以使用负后视(?^来表示字符串的开头。 所以(?表示条件“在它之前没有字符串的开头”。 这就是"(?无法匹配此空白区域的原因

      ↓ "|a|b|c|" 

因为它之前有字符串的开头。

实际上还有一个特殊情况是你的问题的主要观点(?!^) ,这意味着负向前瞻。 这个正则表达式描述了空字符串,后面没有字符串的开头。 它有点不直观,因为之前我们假设字符串的开头(由^表示)放在这里

  ↓ "^|a|b|c|" 

但现在它看起来像是在这里:

  ↓ "|^a|b|c|" 

那么发生了什么? 它是如何工作的?
正如我之前所说,拆分空字符串很棘手。 要理解这一点,你需要看一下没有标记空字符串的字符串,你会看到字符串的开头就在这里

  ↓ "^abc" 

换句话说,正则表达式也考虑在第一个字符(在我们的例子中为"a" )之前的位置作为它的开始,所以

  ↓ "|^a|b|c|" 

使得也有意义并且有效,这就是为什么(?!^)能够看到这个空字符串的原因

  ↓ "|^a|b|c|" 

正好在字符串开始之前,并且不会将其作为有效的分割地点。


无论如何,由于这对于不熟悉正则表达式的开发人员造成混淆,从Java 8开始,我们不必使用技巧(?<=.)(?(?!^)来避免创建开头的空字符串,因为如此问题所述

为什么在Java 8 split中有时会在结果数组的开头删除空字符串?

它会在生成数组的开头自动删除空字符串,因为split使用的长正则表达式表示零长度字符串(如空字符串),因此您现在可以使用"abc".split("")并获取结果["a", "b", "c"]

(1)为什么str2.split(""); 作为[, 1, 2, 3] (2)它是否在文本的开头检测到"" ,如果是这样的话,为什么它最终不会这样做?

通过拆分空字符串,它将返回空字符串作为第一个项目。 如果您正在搜索的字符串中没有定义分隔符,您将获得一个大小为1的数组,即使该字符串为空,它也会保留原始字符串。


(3)究竟是什么意思(?!^)

这是一个否定前瞻断言,断言它不位于字符串开头之前/之后。

 (?! # look ahead to see if there is not: ^ # the beginning of the string ) # end of look-ahead 

你对Negative Lookahead的工作原理是正确的。

 a(?!b) # matches a when not followed by b 

正则表达式:

 (?!^) 

对于输入的开始是负面outlook。 这意味着“在输入开始之前没有定位”。

因为否则空白的正则表达式在开始之前匹配,这个断言会阻止它在那里分裂,因此它只在字符之间分割(不在开始和第一个字符之间)。

实现同样目标的另一个正则表达式是:

 (?<=.) 

这是任何角色的背后,即“在任何角色之后”,我觉得更清楚。