正则表达式详解
1. 基本字符匹配
- 普通字符:大多数字符在正则表达式中表示它们自身,例如
a匹配字符a。 - 特殊字符:如
.、*、+等,它们在正则表达式中有特殊含义。
2. 元字符
.:匹配除换行符外的任意字符。\d:匹配任意数字,等同于[0-9]。\D:匹配任意非数字字符。\w:匹配字母、数字或下划线,等同于[a-zA-Z0-9_]。\W:匹配非字母、数字或下划线的字符。\s:匹配任意空白字符,包括空格、制表符、换行符等。\S:匹配任意非空白字符。
3. 字符类
[abc]:匹配a、b或c中的任意一个字符。[^abc]:匹配除了a、b和c之外的任意字符。[a-z]:匹配任意小写字母。[A-Z]:匹配任意大写字母。[0-9]:匹配任意数字。
4. 量词
*:匹配前面的字符0次或多次。+:匹配前面的字符1次或多次。?:匹配前面的字符0次或1次。{n}:匹配前面的字符恰好n次。{n,}:匹配前面的字符至少n次。{n,m}:匹配前面的字符至少n次,至多m次。
5. 边界匹配
^:匹配行的开始。$:匹配行的结束。\b:匹配单词边界。\B:匹配非单词边界。
6. 分组和捕获
(abc):将abc作为一个整体进行匹配,并创建一个捕获组。(?:abc):非捕获组,只匹配不捕获。
7. 反向引用
\1:引用第一个捕获组的内容。\2:引用第二个捕获组的内容。
示例:
- 匹配邮箱地址:
\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b - 匹配电话号码:
\d{3}-\d{4}-\d{4} - 匹配URL:
https?://[^\s]+ - 匹配HTML标签:
<([a-zA-Z]+)[^>]*>.*?</\1>
正则表达式的应用:
- 文本搜索:在文本编辑器中查找特定的字符串。
- 文本替换:替换文本中的某些部分,如批量修改文件名。
- 数据验证:验证用户输入的数据格式是否正确,如邮箱、电话号码等。
- 数据提取:从文本中提取特定的信息,如从日志文件中提取错误信息。
建议:
- 实践是学习正则表达式的最佳方式。尝试在不同的场景下使用正则表达式,如在文本编辑器、编程语言中进行搜索和替换。
- 使用在线正则表达式测试工具,如regex101.com,可以帮助你理解和测试正则表达式。
- 阅读正则表达式的文档和教程,理解不同元字符和量词的含义和用法。
- 尝试解决实际问题,如编写一个正则表达式来验证用户输入的密码是否符合要求。
示例:
在桌面角色扮演游戏(TRPG,俗称“跑团”)中,玩家需要掷出若干个骰子,根据掷出的结果推进游戏进度。在线上同样可以跑团,方法是由玩家们向机器人发出指令,由机器人随机产生每个需要掷出的骰子的结果。
玩家向机器人发出的指令是一个仅涉及加法和减法的表达式,即对若干个数字进行一系列加法或减法计算。这些数字可以是直接给出的非负整数(数字不超过 1000),也可以是若干个骰子掷出的结果。
“掷骰子”这个动作对应的指令格式为 xdy,表示摇动 x 个 y 面的骰子(1≤x≤1000,2≤y≤1000)。当 x 为 1 时,1 可以省略。
例如指令 2d3+3-d4 的意思是:先掷出 2 个 3 面骰子(你不必考虑现实中是否存在这样的骰子),不妨假设结果为 1 和 3,则 2d3 的结果就是两个骰子的面值之和 4;然后计算 4 + 3,得到结果为 7;再掷出 1 个 4 面骰子,不妨假设结果为 2,则计算 7 - 2 得到最终结果 5。
本题就请你计算玩家输入的指令里,不同种类的骰子需要掷出几个,以及可能得到的结果在什么区间范围内。
输入格式:
输入在一行中给出一条符合题目描述的玩家输入机器人的指令。题目保证指令长度不超过 20000
输出格式:
首先输出不同种类的骰子分别需要掷出几个。每种骰子的信息占一行,依次输出骰子的面数和投掷的数量,按面数从小到大输出。
输入指令保证至少有一个骰子需要掷出。
最后一行输出两个数,表示根据输入指令可以得到的最小结果和最大结果。
同一行数字间以 1 个空格分隔,行首尾不得有多余空格。
题解:
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
String input = "d6+3d5+2-2d3+2d5"; // 示例输入,实际应用中应从控制台读取
Map<Integer, Integer> diceMap = new HashMap<>();
int minSum = 0;
int maxSum = 0;
// 正则表达式匹配所有骰子指令和数字
Pattern pattern = Pattern.compile("(\\d*)d(\\d+)|(\\+|-)(\\d+)");
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
if (matcher.group(2) != null) {
// 匹配到骰子指令,例如 "2d6"
int count = matcher.group(1).isEmpty() ? 1 : Integer.parseInt(matcher.group(1));
int sides = Integer.parseInt(matcher.group(2));
diceMap.put(sides, diceMap.getOrDefault(sides, 0) + count);
// 更新最小值和最大值
minSum += (count > 1) ? (sides * (count - 1)) : 0; // 减去多余的最小值
maxSum += (count > 1) ? (sides * count) : sides;
} else if (matcher.group(3) != null) {
// 匹配到数字,例如 "+3"
int number = Integer.parseInt(matcher.group(4));
minSum += (matcher.group(3).equals("+")) ? number : -number;
maxSum += number; // 最大值只考虑正数
}
}
// 输出每种骰子的数量
for (Map.Entry<Integer, Integer> entry : diceMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
// 输出最小结果和最大结果
System.out.println(minSum + " " + maxSum);
}
}
注:
在Java中,正则表达式中的特殊字符需要进行转义,以便正确地表示它们。在正则表达式中,\d表示匹配任意数字(0-9)。然而,在Java字符串中,反斜杠\本身就是一个转义字符,因此如果你想在字符串中表示一个反斜杠,你需要使用两个反斜杠\\。
当你在Java代码中写"\\d+"时,第一个反斜杠\是用来转义第二个反斜杠\的,这样Java就会将\\解释为一个单独的反斜杠字符。然后,这个单独的反斜杠\再去转义后面的d,告诉Java这是一个正则表达式中的特殊字符\d,而不是普通的字符d。
所以,当你在Java代码中看到"\\d+"时,它实际上是表示正则表达式中的\d+,其中\d匹配任意数字,而+表示前面的元素(在这里是\d)应该出现一次或多次。
总结一下,Java字符串中的"\\d+"实际上对应于正则表达式中的\d+,但由于Java字符串中反斜杠的转义规则,你需要在字符串中写成"\\d+"。
673

被折叠的 条评论
为什么被折叠?



