我有一个应该从控制台读取一些字符串的程序。如果出现String“end”,它应该开始计算并在控制台中写一个String。
我正在阅读的字符串是一个化学方程式。等式用以下两个字符分开:->
。我应该证明两边的原子数量是否相同。我发现了this帖子并尝试实现它,但我对正则表达式有疑问。
例如:
如果在公式之前有一个数字,我的正则表达式可以读取并计算化学方程式:
2 HCl + 2 Na -> 2 NaCl + H2
但是如果没有数字,那么它就不能正确计算:
HCl + Na -> NaCl + H2
我的代码:
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
List<String> list = new ArrayList<String>();
String input = "";
while (!(input.equals("end"))) {
input = s.nextLine();
list.add(input);
}
int before = 0;
int after = 0;
list.remove(list.size() - 1);
for (int i = 0; i < list.size(); i++) {
String string = list.get(i);
string = string.replace("-", "");
String[] splitted = string.split(">");
Pattern firstPattern = Pattern.compile("(\\d+) (\\w+)");
Matcher firstMatcher = firstPattern.matcher(splitted[0]);
while (firstMatcher.find()) {
int element = Integer.parseInt(firstMatcher.group(1));
String count = firstMatcher.group(2);
final Pattern pattern = Pattern.compile("\\d+"); // the regex
final Matcher matcher = pattern.matcher(count); // your string
final ArrayList<Integer> ints = new ArrayList<Integer>(); // results
while (matcher.find()) { // for each match
ints.add(Integer.parseInt(matcher.group())); // convert to
// int
}
for (int j = 0; j < ints.size(); j++) {
before = before + element * ints.get(j);
}
}
Pattern secondPattern = Pattern.compile("(\\d+) (\\w+)");
Matcher secondMatcher = secondPattern.matcher(splitted[1]);
while (secondMatcher.find()) {
int element = Integer.parseInt(secondMatcher.group(1));
String count = secondMatcher.group(2);
final Pattern pattern = Pattern.compile("\\d+"); // the regex
final Matcher matcher = pattern.matcher(count); // your string
final ArrayList<Integer> ints = new ArrayList<Integer>(); // results
while (matcher.find()) { // for each match
ints.add(Integer.parseInt(matcher.group())); // convert to
// int
}
for (int j = 0; j < ints.size(); j++) {
after = after + element * ints.get(j);
}
}
if (before == after) {
System.out.println("formally correct");
} else {
System.out.println("incorrect");
}
}
}
以下是一些用于尝试的化学方程式示例:
输入:
2 HCl + 2 Na - > 2 NaCl + H2
<12> CO2 + 6H2O - > 2 C6H12O6 + 12O2端
输出:
不正确
正式更正
不正确
答案 0 :(得分:2)
我不确定这是否是你需要的。但是为了获得等式的各个部分,可以使用以下regex:
\w+ // matches any word character (equal to [a-zA-Z0-9_])
请点击链接了解详情。要获得字符串的左右部分,我们可以使用"HCl + Na -> NaCl + H2".split("->")
将其拆分。之后我们可以进行计算:
final Pattern pattern = Pattern.compile("\\w+");
Arrays.asList(
"HCl + Na -> NaCl + H2",
"2 HCl + 2 Na -> 2 NaCl + H2",
"12 CO2 + 6 H2O -> 2 C6H12O6 + 12 O2"
).stream().flatMap(s -> Stream.of(s.split("->"))
).peek(s -> System.out.println("part of equation: " + s))
.forEach(s ->
{
Matcher match = pattern.matcher(s);
while (match.find()) {
System.out.println(match.group());
}
}
);
我希望这会有所帮助。
答案 1 :(得分:2)
所以,这是我在你的逻辑中可以找到的问题:
Pattern.compile("(\\d+) (\\w+)")
来匹配任何一方的每个组件。在模式中,您尝试匹配1 or more digits followed by a space followed by 1 or more word characters
。但在那里,数字是可选的。因此,您需要它\\d*
而不是第一个捕获组内容。空间也是可选的。所以你需要在模式中指定相同的。并且为了避免数字与第二个捕获组匹配(因为第一个组变为可选),您需要使用([A-Z]\\w*)
。这确保了数字(如果有)将与第一组本身匹配。因此,用于匹配任何一方的每个组件的模式应为Pattern.compile("(\\d*) ?([A-Z]\\w*)")
。您正在使用Pattern.compile("\\d+")
来匹配原子数(在H2中为2)。如果任何元素都有单个原子,你将错过计算单个原子,即如果你有CaCl2
,你必须把它算作1个原子的Ca和2个Cl的原子。为此,您需要单独匹配每个元素,这可以使用Pattern.compile("[A-Z][a-z]*(\\d*)")
之类的模式完成。
您没有以正确的方式计算总数。将每个元素的分子和原子计数默认为1并将它们乘以每个元素,并将所有产品相加以得到总数。
还有2条建议:
->
分隔。我认为您不需要先删除连字符,然后按>
分割。在进入代码之前尝试自己修改逻辑
这是我定义用于计算一方总计的函数的方式:
private static int calculateCount(String eqPart) {
Matcher matcher = Pattern.compile("(\\d*) ([A-Z]\\w*)").matcher(eqPart);
int totalCount = 0;
while (matcher.find()) {
String moleculeCountStr = matcher.group(1);
int moleculeCount = moleculeCountStr.isEmpty() ? 1 : Integer.parseInt(moleculeCountStr);
String molecule = matcher.group(2);
Matcher moleculeMatcher = Pattern.compile("[A-Z][a-z]*(\\d*)").matcher(molecule);
while (moleculeMatcher.find()) {
String atomCountStr = moleculeMatcher.group(1);
int atomCount = atomCountStr.isEmpty() ? 1 : Integer.parseInt(atomCountStr);
totalCount += moleculeCount * atomCount;
}
}
return totalCount;
}
使用每个拆分结果(->
)调用该函数,并比较总计以查看等式是否正确。