java - 正则表达式从输入字符串中提取表达式
问题描述
我正在尝试使用正则表达式从输入字符串中提取“操作数运算符操作数”格式的表达式。操作数可以是任何单个单词或引用的短语,操作数之间的运算符将是波浪号后跟数字。该表达式可能在输入字符串中出现 n 次。我的正则表达式有什么问题?
package test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ExpressionExtractor {
private static final String operator = "\\s+\\~{1}\\d+\\s+";
private static final String quotedWords = "[\"|'|“][A-Za-zÀ-ü0-9\\\\.\\/\\-,\\*\\s]+[\"|'|“]";
private static final String singleWords = "[A-Za-zÀ-ü0-9\\\\.\\/\\-,\\*]+";
private static final String operand = quotedWords+"|"+singleWords;
private static final Pattern expressionPattern = Pattern.compile("("+operand + operator +operand+")");
private static final Pattern operatorPattern = Pattern.compile(operator);
public static Matcher evaluateExpression(String input) {
return expressionPattern.matcher(input);
}
}
具有预期结果的测试用例:
package test;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import org.junit.Test;
public class ExpressionExtractorUnitTest {
@Test
public void testExpressionExtractor() {
assertEquals(Arrays.asList("firstWord ~20 secondWord"), find("any word firstWord ~20 secondWord one more word"));
assertEquals(Arrays.asList("mother-in-law ~8 long-Word"), find("start of sentence mother-in-law ~8 long-Word one sentence"));
assertEquals(Arrays.asList("firstWord ~7 secondWord", "word ~8 \"complex expression\""),
find("more complex expression firstWord ~7 secondWord with another word ~8 \"complex expression\" continued"));
}
private List<String> find(String expression) {
Matcher matcher = ExpressionExtractor.evaluateExpression(expression);
List<String> tokens = new ArrayList<>();
while (matcher.find()) {
tokens.add(matcher.group());
}
return tokens;
}
}
解决方案
由于您的代码包含一个不错的单元测试,因此建议进行以下修复/更改:
- 如果为 1,则不需要指定字符数,因此“~{1}”可以变为“~”。您不需要转义波浪字符,因此“\s+\~{1}\d+\s+”可以变成“\s+~\d+\s+”。如果你不喜欢“栅栏”,你可以使用另一个字符,例如像这样
String operator = "!s+~!d+!s+".replace('!','\\').
- 我发现引用词的表达太复杂了,无法理解。您可以尝试以引号字符开头的组,然后是 0 个或多个非引号字符,然后是引号。此外,您不需要方括号内的管道
String quotedWords = "[\"|'|“][^\"|'|“]*[\"|'|“]";
- 为了匹配许多替代模式,您必须为每个组添加额外的括号
expressionPattern = Pattern.compile("(" + operand + ")(" +operator + ")(" +operand + ")");
这将使测试通过。但是,您可能会考虑使用像 ANTLR 这样的语法解析器库。在那里,您可以轻松转到嵌套表达式并获取抽象语法树 (AST)
推荐阅读
- docker - 带有 Docker 容器的 MariaDB Galera 集群 - 节点不加入初始化集群
- reporting-services - SSRS:行不在每一页上重复
- yii - Yii1 - CActiveDataProvider 标准未按预期工作
- gitlab - 无法访问自己托管的 gitlab
- wordpress - 在wordpress中注册自定义输入类型时如何隐藏或删除“添加新”子菜单?
- javascript - 每 2 秒重复一次 PHP 函数
- visual-studio - Visual Studio Team Services 在线 - “5 位用户免费”澄清
- ios - Swift Metal MTLCreateSystemDefaultDevice 返回 nil
- java - com.din.OSS 中构造函数的参数 0 需要找不到类型为“java.lang.String”的 bean
- python - 使用 Python 和 Pandas 合并多个 CSV 文件