在多个字符上分割一个字符串

3
我想在下列许多字符之一上分割句子。我的正则表达式可以基于大部分字符进行分割,但不能分割 '[]' (左右方括号)。如果我将字符串 SPECIAL_CHARACTERS_REGEX 更改为 [ :;'=\\()!-\\[\\]],它会开始在字符串中分割整数,而不是分割方括号。如何使正则表达式在方括号而不是整数上分割 ('[]' 表示所有整数)。
另一个相关的问题是,是否有一种方法也可以从字符串中分割数字?例如,9pm 应该分割成 9pm
This:

private static final String SPECIAL_CHARACTERS_REGEX = "[ :;'=\\()!-]";
String rawMessage = "let's meet tomorrow at 9:30p? 7-8pm? i=you go (no Go!) [to do !]"
String[] tokens = rawMessage.split(SPECIAL_CHARACTERS_REGEX);

Gives:

Input: let's meet tomorrow at 9:30p? 7-8pm? i=you go (no Go!) [to do !]
output: [let, s, meet, tomorrow, at, 9, 30p?, 7, 8pm?, i, you, go, , no, Go, , , [to, do, , ]]

同时,

This:

private static final String SPECIAL_CHARACTERS_REGEX = "[ :;'=\\()!-\\[\\]]";
String rawMessage = "let's meet tomorrow at 9:30p? 7-8pm? i=you go (no Go!) [to do !]"
String[] tokens = rawMessage.split(SPECIAL_CHARACTERS_REGEX);

Gives:
let's meet tomorrow at 9:30p? 7-8pm? i=you go (no Go!) [to do !]
[let, s, meet, tomorrow, at, , , , , p, , , , , pm, , i, you, go, , no, , o, , , , to, do]

期望的输出结果:

{"let", "s", "meet", "tomorrow", "at", "9", "30", "p", "7", "8", "pm", "i", "you", "go", "no", "Go", "to", "do"}

你期望的输出是什么? - hwnd
【】在正则表达式中有特殊含义,如果你想将它们作为匹配的一部分使用,就需要对它们进行转义。 - MadProgrammer
我已经将期望的输出添加到帖子中。 - Darth.Vader
我该如何从字符串中分离数字?例如,“9pm”需要被分离成“9”和“pm”。谢谢! - Darth.Vader
4个回答

5
将破折号放在末尾(或开头或转义)是因为否则它将被视为一组字符:
[ :;'=\\()!\\[\\]-]

您原来的正则表达式匹配了![之间的所有字符,包括数字、大写字母以及其他一些符号,例如()等。

为了得到您期望的结果,您可以使用类似以下的表达式:

[ ?:;'=\\()!\\[\\]-]+|(?<=\\d)(?=\\D)

(?<=\d)(?=\D) 的作用是将数字和非数字分离开来(或者您也可以使用 [0-9][^0-9],这应该会更有效率/更快速)

ideone演示


1
请注意,您必须将方括号部分放在 (?<=\\d)(?=\\D) 之前;如果您将它们放在另一个顺序中,即 (?<=\\d)(?=\\D)|[ ?:;'=\\()!\\[\\]-]+,则结果将不同。这是因为像 ' ''?' 等字符既匹配字符集又匹配 \\D。将字符集放在第一位将确保当看到其中一个字符时,它将被视为匹配集合中的字符,因此作为定界符处理,而不是作为“前瞻”留在结果中。 - ajb

5
如果你在字符类的中间留下连字符,你需要对它进行转义。但是最好把它放在字符类的开头或结尾。此外,在这里不需要转义括号(),你可能想在字符类后面使用量词符*+。更新:为了获得您期望的结果,您可以执行以下操作。
private static final String SPECIAL_CHARACTERS_REGEX = "[ :;'?=()!\\[\\]-]+|(?<=\\d)(?=\\D)";
String rawMessage = "let's meet tomorrow at 9:30p? 7-8pm? i=you go (no Go!) [to do !]";
String[] tokens = rawMessage.split(SPECIAL_CHARACTERS_REGEX);
System.out.println(Arrays.toString(tokens));

正则表达式:

[ :;'?=()!\[\]-]+    any character of: ' ', ':', ';', ''', '?',
                       '=', '(', ')', '!', '\[', '\]', '-' (1 or more times)
 |                   OR
  (?<=               look behind to see if there is:
   \d                digits (0-9)
  )                  end of look-behind
   (?=               look ahead to see if there is:
    \D               non-digits (all but 0-9)
   )                 end of look-ahead

请查看演示

输出

[let, s, meet, tomorrow, at, 9, 30, p, 7, 8, pm, i, you, go, no, Go, to, do]

将其进一步推广,我该如何从字符串中分离数字和字母?例如,“30pm”需要被拆分为“30”和“pm”。谢谢! - Darth.Vader
@user721998,请您也看一下我对Jerry答案的评论。 - ajb

1
在正则表达式中使用这个,将会在任何数字后面跟着一个字母的地方进行分割:
(?<=\\d)(?=[A-Za-z])

我已经测试了上述模式。要将其添加到您已有的内容中,请在正则表达式中使用 | 来拆分上述内容或您已有的内容:
String[] parts = s.split("[ :;'=()!\\[\\]-]+|(?<=\\d)(?=[A-Za-z])");

(使用hwnd的答案)。?<=是一个向后查找,如果点号后面的模式匹配,则匹配;?=是一个向前查找,如果点号前面的模式匹配,则匹配。

1

首先介绍字母数字组合之间的空格,例如8pm,在'['和']'特殊字符处使用转义序列进行分割:

String rawMessage  = "let's meet tomorrow at 9:30pm 7-8pm? i=you go (no Go!) [to do !]";
String rawMessage2 = rawMessage.replaceAll("(?<=[0-9])(?=[a-zA-Z])", " ");
String[] tokens  = rawMessage2.split("[ :;'=()!\\[\\]]+");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接