拆分字符串,同时保留分隔符除了转义分隔符(正则表达式)

时间:2013-07-09 10:28:00

标签: java regex regex-negation lookahead lookbehind

如果我有一个字符分隔的字符串,那么就这样说:

a-b-c

我希望保留分隔符,我可以使用look-behind和look-ahead来保留分隔符,例如:

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))))

为什么最后一部分不应该是“除非\之前”?如果' - '之后,那意味着我们介于'\'和' - '之间,所以只有\应该在之前,而不是\\-,但如果我更改正则表达式则不起作用像这样反映:

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

结果:a-b\-c

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

2 个答案:

答案 0 :(得分:1)

虽然这并没有真正回答这个问题,但这解释了外观如何运作。

Lookarounds是锚点:它们不使用文本,但在输入文本中找到位置。你的正则表达式可以用更简单的方式编写:

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

你在这里有四个外观:正面和负面的外观,正面和负面的前瞻。

完整的正则表达式是:

(?<=-)            # 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 \

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

现在,如果我们尝试将该正则表达式与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());
}

答案 1 :(得分:0)

  

为什么最后一部分不应该“除非\之前”?

(?=-(?!(?<=\\-)))) 
    ^here

光标位于-之后,因此"unless \ is before"始终为false,因为我们在当前位置之前始终有-


可能更容易正则表达式

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

  • (?<=(?<!\\\\)-)会检查我们之前是否-之前没有\
  • (?=(?<!\\\\)-)会检查我们之前是否-之前没有\