我希望编写一种方法来解析包含人物姓名及其年龄的字符串。例如:
Manuel 8
Mustafa 16
Zhihao 12
Itsuki 12
Louis 11
Farah 11
即字符串的规范为%N %A
,其中%N
代表名称,%A
代表年龄。
但是,字符串的规范不是固定的(例如,在另一个文档中可以是%N age:%A
或%N (%A)
),因此解析方法应能够将规范作为其参数之一
换句话说,解析方法应该像这样工作:
Data d1 = Parser.parse("Indira 15", "%N %A");
Data d2 = Parser.parse("12 Shu-chen", "%A %N");
Data d3 = Parser.parse("Hana (12)", "%N (%A)");
Data d4 = Parser.parse("Name: Sophia [12]", "Name: %N [%A]");
其中Data
和Parser
的定义如下:
public class Data {
private String name;
private int age;
public Data(String name, int age) {
this.name = name;
this.age = age;
}
// + getter and setter methods.
}
public class Parser {
public static Data parse(String s, String specification) {
// --- What to do here? ---
return (new Data(name, age));
}
}
如何编写Parser.parse
?换句话说,如何使用字符串规范来解析字符串?
答案 0 :(得分:1)
在这里,我们可以有一个表达式并将所需的输出分为两组,例如:
((?:\s+)?([a-z-]+)(?:\s+)?)|(\d+)
我们所需的名称在此([a-z-]+)
组中,年龄信息在此(\d+)
中,其余的可以简单地编写为脚本。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
final String regex = "((?:\\s+)?([a-z-]+)(?:\\s+)?)|(\\d+)";
final String string = "Indira 15\n"
+ "12 Shu-chen\n"
+ "Hana (12)\n"
+ "Sophia [12]\n"
+ " Manuel 8\n"
+ "Mustafa 16\n"
+ "Zhihao 12\n"
+ "Itsuki 12\n"
+ "Louis 11\n"
+ "Farah 11";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
final Matcher matcher = pattern.matcher(string);
while (matcher.find()) {
System.out.println("Full match: " + matcher.group(0));
for (int i = 1; i <= matcher.groupCount(); i++) {
System.out.println("Group " + i + ": " + matcher.group(i));
}
}
jex.im可视化正则表达式:
根据zdim的建议:
(1)我认为(?:\ s +)? (至少一个空格,但整个过程是 可选)与\ s *(可选空格)
相同(2)在第二组空格中,我认为您想在 至少一个空格,所以\ s +。
我们可以大大简化和修改初始表达式,使其类似于:
(\s*([a-z-]+)\s+)|(\d+)
答案 1 :(得分:0)
我将阅读该规范并将其用于解析不属于%N和%A的字符串的所有部分,因为它们只会使您的逻辑复杂化。然后,您必须弄清楚打算对该API施加哪些约束,就好像您不对其不确定性施加约束一样。例如
H'mil99是%N%A模式,但是99岁的Nam H'mil或9岁的H'mil9。
如果您选择名称中没有数字且年龄没有字母的逻辑限制,则通过在[0-9] *上执行matcher.group来识别年龄,并将其与%A和%N,其余为%N
答案 2 :(得分:0)
从specification
构建正则表达式,例如像下面这样。
请注意使用Pattern.quote()
来确保specification
中的特殊字符不会被解释为正则表达式。
public static Data parse(String s, String specification) {
// Determine order of value markers
int nameIdx = specification.indexOf("%N");
if (nameIdx == -1)
throw new IllegalArgumentException("Specification is missing %N: " + specification);
int ageIdx = specification.indexOf("%A");
if (ageIdx == -1)
throw new IllegalArgumentException("Specification is missing %A: " + specification);
// Build regex
String regex;
if (nameIdx < ageIdx) {
regex = Pattern.quote(specification.substring(0, nameIdx)) + "(\\S+)" +
Pattern.quote(specification.substring(nameIdx + 2, ageIdx)) + "(\\d+)" +
Pattern.quote(specification.substring(ageIdx + 2));
} else {
regex = Pattern.quote(specification.substring(0, ageIdx)) + "(\\d+)" +
Pattern.quote(specification.substring(ageIdx + 2, nameIdx)) + "(\\S+)" +
Pattern.quote(specification.substring(nameIdx + 2));
}
// Parse string
Matcher m = Pattern.compile(regex).matcher(s);
if (! m.matches())
throw new IllegalArgumentException("String does not fit specification '" + specification + "': " + s);
String name, age;
if (nameIdx < ageIdx) {
name = m.group(1);
age = m.group(2);
} else {
name = m.group(2);
age = m.group(1);
}
return new Data(name, Integer.parseInt(age));
}
测试
System.out.println(parse("Indira 15", "%N %A"));
System.out.println(parse("12 Shu-chen", "%A %N"));
System.out.println(parse("Hana (12)", "%N (%A)"));
System.out.println(parse("Name: Sophia [12]", "Name: %N [%A]"));
输出(假设toString()
类中实现了Data
)
Data[name=Indira, age=15]
Data[name=Shu-chen, age=12]
Data[name=Hana, age=12]
Data[name=Sophia, age=12]
答案 3 :(得分:0)
这适用于给定的数据,应适用于其他变体。但是其他特殊字符可能无法正确转义。
import java.util.*;
import java.util.regex.*;
public class Parser2 {
public static void main(String[] args) {
Data d1 = Parser.parse("Indira 15", "%N %A");
Data d2 = Parser.parse("12 Shu-chen", "%A %N");
Data d3 = Parser.parse("Hana (12)", "%N (%A)");
Data d4 = Parser.parse("Name: Sophia [12]", "Name: %N [%A]");
System.out.println(d1);
System.out.println(d2);
System.out.println(d3);
System.out.println(d4);
}
}
class Data {
private String name;
private int age;
public Data(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "name = " + name + ", " + "age = " + age;
}
}
class Parser {
private static Map<String, String> spec =
Map.of("%A", "(\\d+)", "%N", "([A-Za-z-]+)");
public static Data parse(String s, String specification) {
specification = specification.replaceAll("\\(", "\\\\(");
specification = specification.replaceAll("\\)", "\\\\)");
specification = specification.replaceAll("\\]", "\\\\]");
specification = specification.replaceAll("\\[", "\\\\[");
for (String r : spec.keySet()) {
specification = specification.replace(r, spec.get(r));
}
Matcher m = Pattern.compile(specification).matcher(s);
String m1 = "", m2 = "";
if (m.find()) {
m1 = m.group(1);
m2 = m.group(2);
} else {
return null;
}
String name;
int age;
if (m1.matches("\\d+")) {
age = Integer.parseInt(m1);
name = m2;
}
else {
age = Integer.parseInt(m2);
name = m1;
}
return (new Data(name, age));
}
}
()和[]被转义,以使您的示例能够正常工作 是正则表达式的特殊字符。
一个捕获的字符串中的所有数字都需要测试 允许对名称和年龄进行适当的转换。
这是一种蛮力的方法,无法很好地扩展。