使用正则表达式组从控制台输入中解析多个字段
Parse multiple fields from console input by using regex groups
我有 Publication
个实体:
public class Publication {
private long id;
private String authorName;
private Topic topic;
private long publicationTime;
private String header;
private String text;
//...
}
其中 Topic
是枚举并且有预装值:
public enum Topic {
SALE, PURCHASE, RENT, SERVICES, DATING;
}
Publication
个实体的规则:
- 作者姓名可以包含拉丁字母和数字,但第一个符号必须是字母。它的长度应该在 4 到 20 个符号之间。
- 用户应该选择一个预安装的主题。
- Header 应包含 10 到 30 个符号。
- 文本应包含 20 到 400 个符号。
用户通过控制台工作并可以编辑发布。
这是用户应该使用的语法:
[author name] [topic] [header] [text]
其中字段之间由空格分隔。
所以我想出了以下正则表达式:
([a-zA-Z]\w{3,19}) (RENT|SALE|PURCHASE|SERVICES|DATING) ((\w|\W|\s){10,30}) ((\w|\W|\s){20,400})
我解析为:
Pattern pattern = Pattern.compile("above regex");
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
String authorName = matcher.group(1);
Topic topic = Topic.valueOf(matcher.group(2));
String header = matcher.group(3);
String text = matcher.group(4);
//...
}
但它失败了,例如这样的输入:
Alexander SALE some header This is a text for some publication
因为 Matcher 找到了四个以上的组,所以我得到:
authorName=Alexander
topic=SALE
header=header three This is a
text=a
而不是:
authorName=Alexander
topic=SALE
header=header three
text=This is a text for some publication
如何解决?
您的输入格式不明确,因此您永远无法成功解析它。您无法确定 [header]
结束和 [text]
开始的位置,因为您允许在两个值中使用 space 个字符。
我建议您更改为输入数据中不允许的分隔符(例如 ;
或 /
)。或者可能需要将 header 封装在您可以搜索的内容中,例如
Alexander SALE {some header} This is a text for some publication
如果你使用我的第二个例子,下面的模式会匹配它:
"([a-zA-Z]\w{3,19}) (RENT|SALE|PURCHASE|SERVICES|DATING) \{((?:\w|\W|\s){10,30})\} ((\w|\W|\s){20,400})"
除了添加 \{...\}
来捕获标题外,我还更正了您的部分模式。最初你有:
((\w|\W|\s){10,30})
但这会创建两个捕获组。为了避免这种情况,我把内组做成non-capturing组加上?:
,如下图:
((?:\w|\W|\s){10,30})
我有 Publication
个实体:
public class Publication {
private long id;
private String authorName;
private Topic topic;
private long publicationTime;
private String header;
private String text;
//...
}
其中 Topic
是枚举并且有预装值:
public enum Topic {
SALE, PURCHASE, RENT, SERVICES, DATING;
}
Publication
个实体的规则:
- 作者姓名可以包含拉丁字母和数字,但第一个符号必须是字母。它的长度应该在 4 到 20 个符号之间。
- 用户应该选择一个预安装的主题。
- Header 应包含 10 到 30 个符号。
- 文本应包含 20 到 400 个符号。
用户通过控制台工作并可以编辑发布。
这是用户应该使用的语法:
[author name] [topic] [header] [text]
其中字段之间由空格分隔。
所以我想出了以下正则表达式:
([a-zA-Z]\w{3,19}) (RENT|SALE|PURCHASE|SERVICES|DATING) ((\w|\W|\s){10,30}) ((\w|\W|\s){20,400})
我解析为:
Pattern pattern = Pattern.compile("above regex");
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
String authorName = matcher.group(1);
Topic topic = Topic.valueOf(matcher.group(2));
String header = matcher.group(3);
String text = matcher.group(4);
//...
}
但它失败了,例如这样的输入:
Alexander SALE some header This is a text for some publication
因为 Matcher 找到了四个以上的组,所以我得到:
authorName=Alexander
topic=SALE
header=header three This is a
text=a
而不是:
authorName=Alexander
topic=SALE
header=header three
text=This is a text for some publication
如何解决?
您的输入格式不明确,因此您永远无法成功解析它。您无法确定 [header]
结束和 [text]
开始的位置,因为您允许在两个值中使用 space 个字符。
我建议您更改为输入数据中不允许的分隔符(例如 ;
或 /
)。或者可能需要将 header 封装在您可以搜索的内容中,例如
Alexander SALE {some header} This is a text for some publication
如果你使用我的第二个例子,下面的模式会匹配它:
"([a-zA-Z]\w{3,19}) (RENT|SALE|PURCHASE|SERVICES|DATING) \{((?:\w|\W|\s){10,30})\} ((\w|\W|\s){20,400})"
除了添加 \{...\}
来捕获标题外,我还更正了您的部分模式。最初你有:
((\w|\W|\s){10,30})
但这会创建两个捕获组。为了避免这种情况,我把内组做成non-capturing组加上?:
,如下图:
((?:\w|\W|\s){10,30})