java - 分割字符串,同时保留除转义分隔符之外的分隔符(正则表达式)

标签 java regex regex-negation regex-lookarounds lookbehind

如果我有一个由字符分隔的字符串,可以这么说:

a-b-c

并且我想保留分隔符,我可以使用后视和前视来保留分隔符本身,例如:

string.split("((?<=-)|(?=-))");

结果

  • a
  • -
  • b
  • -
  • c

现在,如果其中一个分隔符被转义,如下所示:

a-b\-c

我想兑现这次转义,我想出了使用这样的正则表达式:

((?<=-(?!(?<=\\-))) | (?=-(?!(?<=\\-))))  

因此

string.split("((?<=-(?!(?<=\\\\-)))|(?=-(?!(?<=\\\\-))))"):

现在,这有效并导致:

  • a
  • -
  • b\-c

(我稍后用 string.replace("\\", ""); 删除反斜杠,我还没有找到将其包含在正则表达式中的方法)

我的问题是理解问题。
按照我的理解,正则表达式就是,

split ((if '-' is before (unless ('\-' is before))) or (if '-' is after (unless ('\-' is before))))

为什么最后一部分不应该是“除非\在之前”?如果“-”在后面,则意味着我们位于“\”和“-”之间,因此只有 \应该在之前,而不是 \\- ,但如果我更改正则表达式以反射(reflect)这样的情况,它就不起作用:

((?<=-(?!(?<=\\-))) | (?=-(?!(?<=\\))))  

结果:a , - , b\ , -c

这是什么原因呢?我的推理错误在哪里?

最佳答案

虽然这并不能真正回答问题,但这解释了环视是如何工作的。

Lookarounds 是 anchor :它们不消耗文本,而是在输入文本中查找位置。您的正则表达式可以用更简单的方式编写:

(?<=-)(?<!\\-)|(?=-)(?<!\\)

这里有所有四种环视:正向和负向前瞻、正向和负向前瞻。

完整的正则表达式如下:

(?<=-)            # Find a position where what precedes is a dash
(?<!\\-)          # Find a position where what precedes is not \-
|                 # Or
(?=-)             # Find a position where what follows is a dash
(?<!\\)           # Find a position where what precedes is not a \

请注意术语“位置”。请注意, anchor 根本不会在文本中前进。

现在,如果我们尝试将该正则表达式与 a-b\-c 进行匹配:

# Step 1
# Input:    | a-b\-c|
# Position: |^      |
# Regex:    | (?<=-)(?<!\\-)|(?=-)(?<!\\)|
# Position: |^                           |
# No match, try other alternative
# Input:    | a-b\-c|
# Position: |^      |
# Regex:    |(?<=-)(?<!\\-)| (?=-)(?<!\\)|
# Position: |               ^            |
# No match, regex fails
# Advance one position in the input text and try again

# Step 2
# Input:    |a -b\-c|
# Position: | ^     |
# Regex:    | (?<=-)(?<!\\-)|(?=-)(?<!\\)|
# Position: |^                           |
# No match, try other alternative
# Input:    |a -b\-c|
# Position: | ^     |
# Regex:    |(?<=-)(?<!\\-)| (?=-)(?<!\\)|
# Position: |               ^            |
# Match: a "-" follows
# Input:    |a -b\-c|
# Position: | ^     |
# Regex:    |(?<=-)(?<!\\-)|(?=-) (?<!\\)|
# Position: |                    ^       |
# Match: what precedes is not a \
# Input:    |a -b\-c|
# Position: | ^     |
# Regex:    |(?<=-)(?<!\\-)|(?=-)(?<!\\) |
# Position: |                           ^|
# Regex is satisfied

这是一种不使用拆分且不使用环视的替代方案:

[a-z]+(\\-[a-z]+)*|-

您可以在Pattern中使用此正则表达式并使用Matcher:

public static void main(final String... args)
{
    final Pattern pattern
        = Pattern.compile("[a-z]+(\\\\-[a-z]+)*|-");

    final Matcher m = pattern.matcher("a-b\\-c");
    while (m.find())
        System.out.println(m.group());
}

关于java - 分割字符串,同时保留除转义分隔符之外的分隔符(正则表达式),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17545881/

相关文章:

python - 正则表达式匹配但没有评论

javascript - 我怎样才能简单地使用这个数字格式验证正则表达式?

regex - 转到正则表达式以匹配所有不以时间戳开头的行

java - 如何使用 apache POI 复制包含图表的幻灯片?

JavaFX - 在运行时移动矩形?

javascript - 使用正则表达式从函数中删除参数类型

javascript - 将输入字符串与文本/元素匹配并突出显示 react 性

java - 带有继承的Java程序应该如何追溯?

java - 如何将对象流映射到特定类型

MySQL - 需要查找其中没有句号的记录