对非单词字符拆分进行例外处理

时间:2016-09-19 23:02:43

标签: java regex

我有以下正则表达式:

\s+|(?=[^\w'])|(?<=\W)(?=')

我在java中用作:

String[] split = str.split("\\s+|(?=[^\\w'])|(?<=\\W)(?=')");

这基本上允许我根据空格,特殊字符拆分单词并为撇号留下例外,这样我就可以将内容保留在撇号中而不会将其拆分。

当撇号内有正常字符时,这很有效:

Input:
write('A')

Output:
write
(
'A'
)

但是,如果撇号内部有特殊字符,则无法正常工作:

Input:
write('A','(', '=', ',');

Actual output:
write
(
'A'
,
'
(
'
,
'
=
'
,
'
,
'
)
;

Wanted output:
write
(
'A'
,
'('
,
'='
,
','
)
;

有没有办法可以跳过特殊字符的异常 - 如果它们在撇号内,基本上不会跳过它们?

这是我的Regex101:https://regex101.com/r/mL7eL6/3

1 个答案:

答案 0 :(得分:1)

请记住,我正在考虑您要解析的语言的语法:

一种方法是使用先行来确定从当前位置到字符串末尾的撇号数是否均匀。如果可以假设撇号是平衡的,那么这个数字是偶数的位置是“外部”撇号。正则表达式(在Java中),这样的计数是:

String[] split = str.split(
    "\\s+|"+
    "(?=[^\\w'][^']*('[^']*'[^']*)*$)|" +
    "(?<=[^\\w'])(?=[^']*('[^']*'[^']*)*$)|" +
    "(?=('[^']*'[^']*)*$)|" +
    "(?<=')(?=[^']*('[^']*'[^']*)*$)"
);

第一种选择忽略了空格。第二个和第三个分别在(非撇号)特殊字符之前和之后分割字符串,但仅当字符串的其余部分中的撇号数是偶数时。类似地,第四和第五个备选方案分别在前后平衡撇号之前和之后分割字符串。

然而,使用这种方法至少有三个缺点:

  1. 效率不高。前瞻有一个字符串锚的结尾,这将导致大量读取到字符串的末尾。
  2. 它平衡了从右到左而不是从左到右的撇号,这可能是令人惊讶的。 (当然,这只是输入格式错误的问题。)
  3. 正则表达式很复杂。
  4. 使用模式和匹配器可能是更好的选择。正则表达式指定了感兴趣字符串的各个部分,而不是设计一个确定字符串拆分位置的正则表达式:

    Pattern pattern = Pattern.compile(
        "[\\w]+|" +
        "[^\\w']|" +
        "'[^']*'");
    Matcher matcher = pattern.matcher(str);
    while (matcher.find()) {
        System.out.println(matcher.group());
    }
    

    第一种选择是挑选出字母数字字符串。第二个选择不是撇号的单个非字母数字。第三个选择平衡的撇号。 matcher.find()找到与正则表达式匹配的输入的下一部分(如果有)。 matcher.group()返回最后由matcher.find()匹配的子字符串。