如何使用string#split函数来拆分一个字符串,以+、-、*、/、( )和空格作为分隔符,并将它们保留为额外的标记?

5
我需要拆分包含基本数学表达式的字符串,例如:
"(a+b)*c"

" (a - c) / d"
分隔符是+ - * /()和空格,我需要它们作为独立的标记。
基本上结果应该像这样:
"("
"a"
"+"
"b"
")"
"*"
"c" 对于第二个例子:
" "
"("
"a"
" "
"-"
...
我阅读了很多有关类似问题的问题,其中分隔符较少且常见答案是使用零空间正向预查和后顾。
像这样:(?<=X | ?=X)
X代表分隔符,但将它们放在类中如下所示:
[\\Q+-*()\\E/\\s]
不能按所需方式工作。
那么我该如何格式化分隔符以使拆分按我的要求工作?
--- 更新 ---
单词类字符和更长的组合不应被拆分。
例如“ab”“c1”或“12”。
换句话说,我需要与StringTokenizer相同的结果,给出参数“-+*/() ”和true。

2
https://dev59.com/P3E95IYBdhLWcg3wn_Zr - Zutty
a+ab-c1+12 应该如何分割? ab 是一个标记还是由 a*b 组成的一组标记,这部分的结果应该是 a * b 吗?你的字符串中是否可能包含数字? - Pshemo
"ab"应保持不变,同样"c1"和"12"。 - Thiemo Krause
“a__-c”(假设“_”是空格),两个空格应该转换成一个“__”两个空格标记还是两个“_”“_”一个空格标记?我认为应该是一个两个空格标记,因为“12”应该保持不变,但只是想确认一下。 - Pshemo
请返回仅翻译后的文本。 - Thiemo Krause
4个回答

1
尝试使用

将您的数据拆分。
yourString.split("(?<=[\\Q+-*()\\E/\\s])|(?=[\\Q+-*()\\E/\\s])(?<!^)"));

我假设你遇到的问题不在于\\Q+-*()\\E部分,而是在于(?<=X | ?=X)。应该改为(?<=X)|(?=X),因为它应该产生前后查找。

展示程序:"_a+(ab-c1__)+12_" (顺便说一句,代码中的 _ 将被替换为空格。由于 SO 显示两个空格会变成一个,因此必须使用 __ 来表示它们)

String[] tokens = " a+(ab-c1  )+12 "
        .split("(?<=[\\Q+-*()\\E/\\s])|(?=[\\Q+-*()\\E/\\s])(?<!^)");
for (String token :  tokens)
    System.out.println("\"" + token + "\"");

结果
" "
"a"
"+"
"("
"ab"
"-"
"c1"
" "
" "
")"
"+"
"12"
" "

除了你的答案之外,还需要添加"(?<=[\Q+-()\E/\s])|(?=(?!^)[\Q+-()\E/\s])",因为前导定界符(例如括号)会导致空字符串。 - Thiemo Krause
@ThiemoKrause 是的,我早些时候用 (?=[\\Q+-*()\\E/\\s])(?<!^) 更新了我的答案(抱歉,忘记通知你了),但如果您更喜欢 (?=(?!^)[\\Q+-*()\\E/\\s]) 也可以。 - Pshemo

1
如果您是作为学生工作,这是一件事情,但在实践中,这更像是词法分析器和解析器的工作。在C语言中,您可以使用lex和yacc或GNU flex和bison。在Java中,您可以使用ANTLR或JavaCC。
但首先,编写一个BNF语法来描述您期望的输入(通常称为输入“语言”)。

0

试试这个:

[-+*()\\s]

破折号必须放在字符类的开头或结尾,以免表示一个范围。其他字符在字符类中不需要转义(我猜你之前用\\Q\\E是想要做这个),因为大多数字符在字符类中都被直接使用。

另外,我之前不知道(?<=X|?=X)这种语法。如果它有效,那太好了。但如果无效的话,可以尝试下面这个等价的扩展,我知道这个语法是有效的:

(?:(?<=X)|(?=X))

我将表达式更改为(?:(?<=[-+/()\s]) | (?=[-+/()\s])),但如果输入字符串中没有空格,则不会进行单个拆分,例如:(b+2)*6。 - Thiemo Krause

0

您可以使用以下正则表达式:

\s*(?<=[()+*/a-z-])\s*

?<= 表示零宽断言,即匹配但不包括在组中。 \s* 将处理尾随空格。

代码示例:

String a = " (a - c) / d *       x   ";
String regex = "\\s*(?<=[()+*/a-z-])\\s*";
String[] split = a.split(regex);
System.out.println(Arrays.toString(split));

输出:

[ (, a, -, c, ), /, d, *, x]

请仅返回翻译后的文本:以下是有关编程的内容,请将正则表达式在顶部修复。 - nhahtdh
@nhahtdh 为了清楚明白(以及消除疑虑),我通常会对所有内容进行转义,但在这种情况下,您的方式同样适用。有了您的建议,我更新了答案。谢谢! - acdcjunior
我不知道如何转义所有内容会让它更清晰,但当你怀疑时我理解为什么你这样做。对我而言,在字符类中大多数字符都被转义时跟踪这些字符更难了。 - nhahtdh
@nhahtdh 当读者也不确定何时需要转义时,这样讲更清楚 :) 但我完全同意你的观点。 - acdcjunior
抱歉,我忘了提到更长的词类字符组合应该保留在一个标记中。已添加。 - Thiemo Krause

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