(Java) 如何使用 .matches() 检查字符串中的两位或多位整数?
(Java) How do you check a string for two or more digit integers using .matches()?
此程序的 objective 是 return 来自给定公式(作为字符串)的原子质量,使用包含元素及其原子质量的 CSV 文件。
我针对这个特定问题的代码是这样的:
double mass = 0.0;
Map<String, Double> perTableMap = fileReader(periodicTable);
Map<String, Integer> atomMap = getAtoms(formula);
for (Map.Entry<String, Double> periEntry : perTableMap.entrySet()) {
for (Map.Entry<String, Integer> atomEntry : atomMap.entrySet()) {
if (atomEntry.getKey().equals(periEntry.getKey())) {
mass += periEntry.getValue() * atomEntry.getValue();
}
}
}
return mass;
我有另一种方法“fileReader”,它从英里获取数据,returns 一个地图,其中元素作为键,质量作为值,这个工作正常。
此代码也适用于原子数为个位数的“公式”,例如“OCS”、“C4H4AsH”和“Fe2O3”。
但是,当原子数量为2位或更多位数字时,它只读取该数字的第一位数字。
例如:对于“RuSH2112”,它应该是 Ru1 + S1 + H2112,但输出是 Ru1 + S1 + H2.
我认为我的方法“getAtoms”有问题,它说“!!! 这里!!!”,这是它的代码:
public static Map<String, Integer> getAtoms(String formula) {
// LinkedHashMap stores in insertion order
Map<String, Integer> newMap = new LinkedHashMap<>();
for (int i = 0; i < formula.length(); i++) {
int count = 0;
// convert string to char
char c = formula.charAt(i);
// convert char to string
String a = String.valueOf(c);
// check formula for upper case values
if (a.matches("[A-Z]")) {
for (int j = i + 1; j < formula.length(); j++) {
char d = formula.charAt(j);
String b = String.valueOf(d);
// check formula for lower case values
if (b.matches("[a-z]")) {
a += b;
if (newMap.get(a) == null)
newMap.put(a, 1);
else
newMap.put(a, newMap.get(a) + 1);
count = 1;
}
// check formula for integer values (the end of each molecule)
// !!! HERE !!!
else if (b.matches("[\d]")) {
int k = Integer.parseInt(b);
newMap.put(a, k);
count = 1;
}
else {
i = j - 1;
break;
}
}
// put values into a map
if (count == 0) {
if (newMap.get(a) == null)
newMap.put(a, 1);
else
newMap.put(a, newMap.get(a) + 1);
}
}
}
return newMap;
}
是否有另一种说法 .matches("[\d]")) 因为我认为它只使用一个数字?
我已经重新实现了你的方法getAtom()
。对它所做的主要更改是,它不是逐个字符地处理 formula,而是将 formula 分成代表大写字母的块, 大小写字母的组合,或数字。
这是它的代码:
String[] elementsAndIndices = formula.split("(?<=\p{Lower})(?=\p{Upper})|(?<=\p{Upper})(?=\p{Upper})|(?<=\D)(?=\d)|(?<=\d)(?=\D)");
让我们来看看这里发生了什么:
- \d - 一个数字:[0-9];
- \D - 一个 non-digit: [^0-9];
- \p{Lower} - lower-case 字母字符:[a-z];
- \p{Upper} - 一个 upper-case 字母字符:[A-Z];
- \p{Alpha} - 一个字母字符:[\p{Lower}\p{Upper}];
以问号开头的特殊构造称为lookbehind(?<=\p{Lower}
)和lookahead (?=\p{Upper}
)。两者都匹配 zero-length string 允许以我上面描述的方式拆分 formula 而不会丢失任何符号(您可以阅读更多关于他们的信息 here).
用于拆分公式的lookbehind和lookbehind组合的含义:
(?<=\p{Lower})(?=\p{Upper}) - 匹配 lower-case 字符 [=18= 之间的 zero-length 字符串] 和一个 upper-case 字符 \p{Upper}
;
(?<=\p{Upper})(?=\p{Upper}) - 匹配两个 upper-case 字符之间边界上的 zero-length 字符串 \p{Upper}
;
(?<=\D)(?=\d) - 匹配 non-digit \D
和数字 [=22 之间的 zero-length 字符串=];
(?<=\d)(?=\D) - 匹配数字 \d
和 non-digit [=21 之间的 zero-length 字符串=].
方法merge()用于更新地图。它需要三个参数:键、值和重映射函数。如果给定的键是 absent(或者这个键与 null 值相关联)那么这个键将与 given 相关联值。用于合并两个值的重新映射函数将 仅评估 如果提供的键已经存在并且它的值为 not null .
elements.merge(elementsAndIndices[i], 1, Integer::sum);
上面显示的代码行将值 1
与键 elementsAndIndices[i]
相关联,如果它不存在于地图中,否则,它会将现有值与 1
合并生成和。方法参考 Integer::sum
等价于 lambda (val1, val2) -> val1 + val2;
.
public static Map<String, Integer> getAtoms(String formula) {
Map<String, Integer> elements = new LinkedHashMap<>();
String[] elementsAndIndices =
formula.split("(?<=\p{Lower})(?=\p{Upper})|(?<=\p{Upper})(?=\p{Upper})|(?<=\D)(?=\d)|(?<=\d)(?=\D)");
for (int i = 0; i < elementsAndIndices.length; i++) {
if (elementsAndIndices[i].matches("\p{Alpha}+")) {
if (i == elementsAndIndices.length - 1 || !elementsAndIndices[i + 1].matches("\d+")) {
elements.merge(elementsAndIndices[i], 1, Integer::sum);
} else {
elements.merge(elementsAndIndices[i], Integer.parseInt(elementsAndIndices[i + 1]), Integer::sum);
i++;
}
}
}
return elements;
}
public static void main(String[] args) {
System.out.println(getAtoms("C6H12O6"));
System.out.println(getAtoms("NH3"));
System.out.println(getAtoms("RuSH2112"));
}
输出
{C=6, H=12, O=6}
{N=1, H=3}
{Ru=1, S=1, H=2112}
此程序的 objective 是 return 来自给定公式(作为字符串)的原子质量,使用包含元素及其原子质量的 CSV 文件。
我针对这个特定问题的代码是这样的:
double mass = 0.0;
Map<String, Double> perTableMap = fileReader(periodicTable);
Map<String, Integer> atomMap = getAtoms(formula);
for (Map.Entry<String, Double> periEntry : perTableMap.entrySet()) {
for (Map.Entry<String, Integer> atomEntry : atomMap.entrySet()) {
if (atomEntry.getKey().equals(periEntry.getKey())) {
mass += periEntry.getValue() * atomEntry.getValue();
}
}
}
return mass;
我有另一种方法“fileReader”,它从英里获取数据,returns 一个地图,其中元素作为键,质量作为值,这个工作正常。
此代码也适用于原子数为个位数的“公式”,例如“OCS”、“C4H4AsH”和“Fe2O3”。
但是,当原子数量为2位或更多位数字时,它只读取该数字的第一位数字。 例如:对于“RuSH2112”,它应该是 Ru1 + S1 + H2112,但输出是 Ru1 + S1 + H2.
我认为我的方法“getAtoms”有问题,它说“!!! 这里!!!”,这是它的代码:
public static Map<String, Integer> getAtoms(String formula) {
// LinkedHashMap stores in insertion order
Map<String, Integer> newMap = new LinkedHashMap<>();
for (int i = 0; i < formula.length(); i++) {
int count = 0;
// convert string to char
char c = formula.charAt(i);
// convert char to string
String a = String.valueOf(c);
// check formula for upper case values
if (a.matches("[A-Z]")) {
for (int j = i + 1; j < formula.length(); j++) {
char d = formula.charAt(j);
String b = String.valueOf(d);
// check formula for lower case values
if (b.matches("[a-z]")) {
a += b;
if (newMap.get(a) == null)
newMap.put(a, 1);
else
newMap.put(a, newMap.get(a) + 1);
count = 1;
}
// check formula for integer values (the end of each molecule)
// !!! HERE !!!
else if (b.matches("[\d]")) {
int k = Integer.parseInt(b);
newMap.put(a, k);
count = 1;
}
else {
i = j - 1;
break;
}
}
// put values into a map
if (count == 0) {
if (newMap.get(a) == null)
newMap.put(a, 1);
else
newMap.put(a, newMap.get(a) + 1);
}
}
}
return newMap;
}
是否有另一种说法 .matches("[\d]")) 因为我认为它只使用一个数字?
我已经重新实现了你的方法getAtom()
。对它所做的主要更改是,它不是逐个字符地处理 formula,而是将 formula 分成代表大写字母的块, 大小写字母的组合,或数字。
这是它的代码:
String[] elementsAndIndices = formula.split("(?<=\p{Lower})(?=\p{Upper})|(?<=\p{Upper})(?=\p{Upper})|(?<=\D)(?=\d)|(?<=\d)(?=\D)");
让我们来看看这里发生了什么:
- \d - 一个数字:[0-9];
- \D - 一个 non-digit: [^0-9];
- \p{Lower} - lower-case 字母字符:[a-z];
- \p{Upper} - 一个 upper-case 字母字符:[A-Z];
- \p{Alpha} - 一个字母字符:[\p{Lower}\p{Upper}];
以问号开头的特殊构造称为lookbehind(?<=\p{Lower}
)和lookahead (?=\p{Upper}
)。两者都匹配 zero-length string 允许以我上面描述的方式拆分 formula 而不会丢失任何符号(您可以阅读更多关于他们的信息 here).
用于拆分公式的lookbehind和lookbehind组合的含义:
(?<=\p{Lower})(?=\p{Upper}) - 匹配 lower-case 字符 [=18= 之间的 zero-length 字符串] 和一个 upper-case 字符
\p{Upper}
;(?<=\p{Upper})(?=\p{Upper}) - 匹配两个 upper-case 字符之间边界上的 zero-length 字符串
\p{Upper}
;(?<=\D)(?=\d) - 匹配 non-digit
\D
和数字 [=22 之间的 zero-length 字符串=];(?<=\d)(?=\D) - 匹配数字
\d
和 non-digit [=21 之间的 zero-length 字符串=].
方法merge()用于更新地图。它需要三个参数:键、值和重映射函数。如果给定的键是 absent(或者这个键与 null 值相关联)那么这个键将与 given 相关联值。用于合并两个值的重新映射函数将 仅评估 如果提供的键已经存在并且它的值为 not null .
elements.merge(elementsAndIndices[i], 1, Integer::sum);
上面显示的代码行将值 1
与键 elementsAndIndices[i]
相关联,如果它不存在于地图中,否则,它会将现有值与 1
合并生成和。方法参考 Integer::sum
等价于 lambda (val1, val2) -> val1 + val2;
.
public static Map<String, Integer> getAtoms(String formula) {
Map<String, Integer> elements = new LinkedHashMap<>();
String[] elementsAndIndices =
formula.split("(?<=\p{Lower})(?=\p{Upper})|(?<=\p{Upper})(?=\p{Upper})|(?<=\D)(?=\d)|(?<=\d)(?=\D)");
for (int i = 0; i < elementsAndIndices.length; i++) {
if (elementsAndIndices[i].matches("\p{Alpha}+")) {
if (i == elementsAndIndices.length - 1 || !elementsAndIndices[i + 1].matches("\d+")) {
elements.merge(elementsAndIndices[i], 1, Integer::sum);
} else {
elements.merge(elementsAndIndices[i], Integer.parseInt(elementsAndIndices[i + 1]), Integer::sum);
i++;
}
}
}
return elements;
}
public static void main(String[] args) {
System.out.println(getAtoms("C6H12O6"));
System.out.println(getAtoms("NH3"));
System.out.println(getAtoms("RuSH2112"));
}
输出
{C=6, H=12, O=6}
{N=1, H=3}
{Ru=1, S=1, H=2112}