文章目录
- 题目
- 项目层级结构
- 解答
- 已完成的部分简介
- 未完成的部分概述
- 代码部分
- DidYourTypeCorrectly.java
- FormModel.java
- IntelligentRecognition.java
- MVCWindow.java
- Plaint.java
- 运行结果截图
- 结语
题目
模拟顺风地址智能识别,对用户输入的信息,包括:姓名、地址、邮政编码、身份证号码、电话号码、电子邮箱等文本信息进行解析,并进行初步的合法性判断。
- 基础的:文本信息放在文件,代码正确,可扩展性好(考核知识点:面向对象+正则表达式(P233、P285)+I/O+Scanner(P239))
- 进阶的:界面友好,代码正确,可扩展性好(考核知识点:面向对象+正则表达式(P233、P285)+MVC模式(P298)+Swing+Scanner(P239))
样例视图如下
项目层级结构
├─.idea
│ .gitignore
│ encodings.xml
│ misc.xml
│ modules.xml
│ uiDesigner.xml
│ workspace.xml
│
├─out
│ └─production
│ └─DidYourTypeItCorrectly
│ DidYourTypeCorrectly.class
│ FormModel.class
│ icon.png
│ IntelligentRecognition.class
│ MVCWindow.class
│ Plaint$1.class
│ Plaint.class
│ UI.png
│
└─src
DidYourTypeCorrectly.java
FormModel.java
icon.png
IntelligentRecognition.java
MVCWindow.java
Plaint.java
UI.png
解答
下面简单介绍一下这个项目已完成和未完成的地方~
已完成的部分简介
-
友好、黑色简约的UI
-
可扩展性较好,后续可填加别的字段如银行卡信息等
-
使用MVC模式构建(FormModal \ MVCWindow \ IntelligentRecognition)
-
代码健壮性良好。用户输入字符串不需要用空格来分割、也不需要使用字段前缀,如姓名张三地址汕头大学等。
-
友好的识别提示,用户点击了识别后会在右边出现一个弹框,若右边的属性全部匹配成功则会弹出“成功”否则未“失败”
未完成的部分概述
- 使用JavaFx来构建UI页面,JFrame太受局限了,不能在最大程度上优化页面UI
- 适用国家仅限中国。若输入英文名、英文的地址、别国的邮编、别国的手机号可能会出现错误。
- 未能完全匹配姓名(百家姓的Unicode编码不全)
代码部分
根据上面项目的层级结构一共有5个java源文件,下面将一一展示出来
DidYourTypeCorrectly.java
/*
* @Author: hiddenSharp429 z404878860@163.com
* @Date: 2023-05-17 18:14:42
* @LastEditors: hiddenSharp429 z404878860@163.com
* @LastEditTime: 2023-06-06 20:35:24
* @FilePath: \appe:\java\DidYourTypeItCorrectly\src\FormModel.java
* @Description: "Java 作业4-智能识别"
*/
import java.awt.*;
public class DidYourTypeCorrectly {
public static void main(String[] args) {
MVCWindow window = new MVCWindow();//创建窗口
window.setVisible(true);//显示窗口
}
}
FormModel.java
public class FormModel {
String Uname, address, zipCode, identity, phone, email;
public FormModel(String Uname, String address, String zipCode, String identity, String phone, String email) {
this.Uname = Uname;
this.address = address;
this.zipCode = zipCode;
this.identity = identity;
this.phone = phone;
this.email = email;
}
}
IntelligentRecognition.java
/*
* @Author: hiddenSharp429 z404878860@163.com
* @Date: 2023-05-17 18:08:09
* @LastEditors: hiddenSharp429 z404878860@163.com
* @LastEditTime: 2023-06-06 20:35:50
* @FilePath: \appe:\java\DidYourTypeItCorrectly\src\IntelligentRecognition.java
* @Description: ""
*/
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.SplittableRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class IntelligentRecognition implements ActionListener {
String Input;
String Output;
String regex;
Pattern pattern;
Matcher matcher;
MVCWindow mvcWindow;
FormModel formModel;
public static String deleteChars(String input, int startIndex, int endIndex) {
StringBuilder stringBuilder = new StringBuilder(input);
stringBuilder.delete(startIndex, endIndex + 1);
return stringBuilder.toString();
}
public void setMvcWindow(MVCWindow mvcWindow) {
this.mvcWindow = mvcWindow;
}
public String getUname(String Input) {
Output = "";
//百家姓的Unicode编码
String[] surnames = {
"\u795D", // 祝
"\u5F20", // 张
"\u5B59", // 孙
"\u674E", // 李
"\u8D75", // 朱
"\u90B9", // 马
"\u8881", // 宋
"\u5929", // 天
"\u51AF", // 冯
"\u6C88", // 沈
"\u8D3E", // 任
"\u9EC4", // 黄
"\u90D1", // 郑
"\u9A6C", // 马
"\u6768", // 杨
"\u963F", // 阿
"\u5434", // 吴
"\u5468", // 周
"\u5433", // 吴
"\u90AC", // 郭
"\u7BA1", // 管
"\u5B54", // 孙
"\u6797", // 林
"\u4F55", // 何
"\u6731", // 朱
"\u9C81", // 谢
"\u9648", // 陈
"\u8C22", // 谢
"\u4F59", // 余
"\u6BDB", // 毛
"\u82CF", // 苏
"\u859B", // 谢
"\u6D2A", // 浩
"\u8D56", // 赵
"\u7F57", // 罗
"\u7AA6", // 程
"\u9B4F", // 申
"\u987E", // 顾
"\u9AD8", // 高
"\u9F50", // 邓
"\u90ED", // 郭
"\u5510", // 唐
"\u5B5F", // 宋
"\u7A0B", // 程
"\u738B", // 王
"\u8C22", // 谢
"\u6C34", // 水
"\u9E3F", // 黄
"\u5218", // 刘
"\u6234", // 戴
"\u79E6", // 秦
"\u9976", // 龙
"\u4FDE", // 俞
"\u6881", // 梁
"\u9C81", // 谢
"\u7A46", // 穆
"\u9F9A", // 龚
"\u8C2F", // 谯
"\u66FE", // 曾
"\u6734", // 李
"\u8521", // 蔡
"\u7AEF", // 端
"\u5B8B", // 宋
"\u79E6", // 秦
"\u6234", // 戴
"\u5433", // 吴
"\u9C81", // 谢
"\u4E8E", // 于
"\u5362", // 卢
"\u7F57" // 罗
};
String regex = "(" + String.join("|", surnames) + ")[\\u4E00-\\u9FA5]{1,2}";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(Input);
while (matcher.find()) {
Output = matcher.group();
System.out.println(Output);
this.Input = deleteChars(Input, matcher.start(), matcher.end() - 1);
}
return Output;
}
public String getAddress(String Input) {
Output = "";
// 中国地址格式:省市区县街道门牌号
regex = "([\\u4e00-\\u9fa5]+省)?([\\u4e00-\\u9fa5]+市)?([\\u4e00-\\u9fa5]+区)+([\\u4e00-\\u9fa5]+县)?([\\u4e00-\\u9fa5]+街道)?([\\u4e00-\\u9fa5\\w]+号)?";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(Input);
while (matcher.find()) {
Output = matcher.group();
System.out.println(Output);
this.Input = deleteChars(Input, matcher.start(), matcher.end() - 1);
}
return Output;
}
public String getZipcode(String Input) {
Output = "";
regex = "(10|20|30|40|01|02|03|04|05|06|07|11|12|13|15|16|21|22|23|24|25|27|31|32|33|34|35|36|41|42|43|44|45|46|47|51|52|53|54|55|56|57|61|62|63|64|65|66|67|71|72|73|74|75|81|83|84|85)\\d{4}";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(Input);
while (matcher.find()) {
Output = matcher.group();
System.out.println(Output);
this.Input = deleteChars(Input, matcher.start(), matcher.end() - 1);
}
return Output;
}
public String getIdentity(String Input) {
Output = "";
//中国身份证号码六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码
regex = "(1|2|3|4|5|6|8)[1-9]{3}0[1-2]{2}[0-9]{3}[0-1][0-9]{6}(0-9|X)";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(Input);
while (matcher.find()) {
Output = matcher.group();
System.out.println(Output);
this.Input = deleteChars(Input, matcher.start(), matcher.end() - 1);
}
return Output;
}
public String getPhone(String Input) {
Output = "";
regex = "(133|153|180|181|189|177|130|131|132|155|156|185|186|145|176|134|135|136|137|138|139|150|151|152|157|158|159|182|183|184|187|188|147|178|170|171|172|173|174|175|176|177|178|179|166|198|199)\\d{8}";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(Input);
while (matcher.find()) {
Output = matcher.group();
System.out.println(Output);
this.Input = deleteChars(Input, matcher.start(), matcher.end() - 1);
}
return Output;
}
public String getEmail(String Input) {
Output = "";
regex = "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(Input);
while (matcher.find()) {
Output = matcher.group();
System.out.println(Output);
this.Input = deleteChars(Input, matcher.start(), matcher.end() - 1);
}
return Output;
}
@Override
public void actionPerformed(ActionEvent e) {
Input = mvcWindow.textArea.getText();
String Uname, address, zipCode, identity, phone, email;
/*
用正则表达式解析Input字符串
输入如:“张三广东省深圳市宝安区西乡街道泰华阳光海hiddensharp@outlook.com1591977326536250120030429481X518102”
解析出姓名,地址,邮编,身份证号,电话号码,电子邮箱等信息,
顺序可打乱,但是必须包含姓名,地址,邮编,身份证号,电话号码,电子邮箱等信息
*/
email = getEmail(Input);
phone = getPhone(Input);
identity = getIdentity(Input);
zipCode = getZipcode(Input);
Uname = getUname(Input);
address = getAddress(Input);
checkInfo(Uname,address,zipCode,identity,phone,email);
formModel = new FormModel(Uname, address, zipCode, identity, phone, email);
mvcWindow.Uname.setText(formModel.Uname);
mvcWindow.address.setText(formModel.address);
mvcWindow.zipCode.setText(formModel.zipCode);
mvcWindow.identity.setText(formModel.identity);
mvcWindow.phone.setText(formModel.phone);
mvcWindow.email.setText(formModel.email);
}
public void checkInfo(String Uname,String address,String zipCode,String identity,String phone,String email){
//检查信息是否完整
if(Uname.equals("")||address.equals("")||zipCode.equals("")||identity.equals("")||phone.equals("")||email.equals("")){
JOptionPane.showMessageDialog(null, "信息不完整", "提示", JOptionPane.ERROR_MESSAGE);
}
else{
JOptionPane.showMessageDialog(null, "信息完整", "提示", JOptionPane.INFORMATION_MESSAGE);
}
}
}
MVCWindow.java
/*
* @Author: hiddenSharp429 z404878860@163.com
* @Date: 2023-05-17 18:07:27
* @LastEditors: hiddenSharp429 z404878860@163.com
* @LastEditTime: 2023-06-06 20:35:58
* @FilePath: \appe:\java\DidYourTypeItCorrectly\src\MVCWindow.java
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import javax.swing.*;
import java.awt.*;
public class MVCWindow extends JFrame {
FormModel model; // 模型
IntelligentRecognition controller; // 控制器
JTextArea textArea; // 显示信息
JTextField Uname, address, zipCode, identity, phone, email; // 输入的信息
JButton button; // 按钮
JLabel Title; // 标题
JLabel ending; // 结尾
int TitleSize = 50; // 标题大小
int ItemSize = 20; // 输入框大小
Font TitleFont = new Font("微软雅黑", Font.BOLD, TitleSize); // 标题字体
Font ItemFont = new Font("微软雅黑", Font.PLAIN, ItemSize); // 输入框字体
MVCWindow() {
init();
}
void init() {
// 设置窗口
setTitle("智能识别系统");// 设置标题
setBackground(Color.WHITE);
setBounds(100, 100, 1000, 700);// 设置窗口大小
setIconImage(getToolkit().getImage("src/icon.png"));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 设置关闭窗口时的操作
setResizable(false);// 设置窗口不可改变大小
// 设置组件
Title = new JLabel("智能识别系统");
Title.setFont(TitleFont);
textArea = new JTextArea(17, 14);
textArea.setLineWrap(true);// 自动换行
Uname = new JTextField(15);
address = new JTextField(15);
zipCode = new JTextField(15);
identity = new JTextField(15);
phone = new JTextField(15);
email = new JTextField(15);
button = new JButton("识别");
// 设置布局
setLayout(new BorderLayout());
// 设置标题面板
JPanel titlePanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
titlePanel.setBackground(Color.DARK_GRAY);
titlePanel.add(Title);
titlePanel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));
add(titlePanel, BorderLayout.NORTH);
// 设置表单面板
JPanel formPanel = new JPanel(new GridBagLayout());
formPanel.setBackground(Color.WHITE);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = GridBagConstraints.RELATIVE;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = new Insets(5, 5, 5, 5);
// 设置输入面板
JPanel inputPanel = new JPanel(new BorderLayout());
textArea.setBackground(Color.WHITE);
textArea.setFont(ItemFont);
textArea.setToolTipText("显示识别结果");
inputPanel.add(textArea, BorderLayout.NORTH);
inputPanel.add(button, BorderLayout.SOUTH);
inputPanel.setBackground(Color.WHITE);
add(inputPanel, BorderLayout.WEST);
formPanel.add(new JLabel("姓名"), gbc);
formPanel.add(Uname, gbc);
formPanel.add(new JLabel("地址"), gbc);
formPanel.add(address, gbc);
formPanel.add(new JLabel("邮编"), gbc);
formPanel.add(zipCode, gbc);
formPanel.add(new JLabel("身份证号"), gbc);
formPanel.add(identity, gbc);
formPanel.add(new JLabel("电话号码"), gbc);
formPanel.add(phone, gbc);
formPanel.add(new JLabel("电子邮箱"), gbc);
formPanel.add(email, gbc);
add(formPanel, BorderLayout.EAST);
// 设置中间面板
Plaint plaint = new Plaint();
plaint.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));
add(plaint, BorderLayout.CENTER);
// 设置页底面板
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
bottomPanel.setBackground(Color.DARK_GRAY);
ending = new JLabel("Author: hiddensharp");
ending.setFont(new Font("微软雅黑", Font.PLAIN, 15));
ending.setForeground(Color.WHITE);
ending.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));
bottomPanel.add(ending);
add(bottomPanel, BorderLayout.SOUTH);
// 设置字体颜色
Title.setForeground(Color.WHITE);
button.setForeground(Color.BLACK);
Uname.setForeground(Color.BLACK);
address.setForeground(Color.BLACK);
zipCode.setForeground(Color.BLACK);
identity.setForeground(Color.BLACK);
phone.setForeground(Color.BLACK);
email.setForeground(Color.BLACK);
// 设置输入框样式
Uname.setFont(ItemFont);
address.setFont(ItemFont);
zipCode.setFont(ItemFont);
identity.setFont(ItemFont);
phone.setFont(ItemFont);
email.setFont(ItemFont);
// 设置按钮样式
button.setBackground(Color.WHITE);
button.setFocusPainted(false);
button.setPreferredSize(new Dimension(100, 50));
ImageIcon buttonIcon = new ImageIcon("src/icon.png");
Image buttonIconImage = buttonIcon.getImage();
Image scaledImage = buttonIconImage.getScaledInstance(50, 50, Image.SCALE_SMOOTH);
buttonIcon = new ImageIcon(scaledImage);
button.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));
button.setIcon(buttonIcon);
button.setFont(new Font("微软雅黑", Font.BOLD, 20));
button.setIconTextGap(100);
// 创建控制器
controller = new IntelligentRecognition();
// 添加监听器
button.addActionListener(controller);
// 设置控制器的视图
controller.setMvcWindow(this);
}
}
Plaint.java
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
/*author:命运的信徒
* date:2019.7.18
* arm:java动态绘图的方法
*/
public class Plaint extends JPanel {
private List<Integer> values; // 存储数据的集合,线程不安全
private static final int MAX_VALUE = 200; // 最大值(限制里面的y数据)
private static final int MAX_COUNT_OF_VALUES = 50; // 集合的最大容量
public Plaint() {
//一个线程安全的集合
values = Collections.synchronizedList(new ArrayList<Integer>());
// 使用线程的目的,动态的,可以往集合里面添加和去除数据
new Thread(new Runnable() {
public void run() {
//一个随机数,准确的说是小于200的
Random rand = new Random();
try {
while (true) {
//生成的数添加集合,如果集合里面的数据多了就剔除数据
addValue(rand.nextInt(MAX_VALUE)); // 产生一个数据,并模拟接收并放到容器里.
//这个是一个重绘的方法,是线程安全的;可以调用paintComponent(Graphics g) 方法
repaint();
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//准备绘制
Graphics2D g2d = (Graphics2D) g;
//设置绘制线条的质量
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//设置宽高
int w = getWidth();
int h = getHeight();
//设置x轴方向的单位长度;如果宽400px,设置最大的数据容量是50;那么一个数据就占据8px
int xDelta = w / MAX_COUNT_OF_VALUES;
//这个是集合的实时长度,肯定是小于或等于MAX_COUNT_OF_VALUES
int length = values.size();
//对集合里面的数据进行绘制,第一个点和第二个点要连线
for (int i = 0; i < length - 1; ++i) {
/*
* x轴的位置:xDelta * (MAX_COUNT_OF_VALUES - length + i) 如果集合的数据没有溢出来,一定是最后一个是最右边,第一个是集合的最大长度-集合当前长度+1;
* y轴的位置:normalizeValueForYAxis(values.get(i), h)
* 前一个数据和后一个数据相连接
*/
g2d.drawLine(xDelta * (MAX_COUNT_OF_VALUES - length + i), normalizeValueForYAxis(values.get(i), h),
xDelta * (MAX_COUNT_OF_VALUES - length + i + 1), normalizeValueForYAxis(values.get(i + 1), h));
}
}
/**
* 接收到的数据放入内存.
* @param value
*/
private void addValue(int value) {
// 循环的使用一个接收数据的空间.
// 最好是实现一个循环数组,而不是偷懒的使用ArrayList.
if (values.size() > MAX_COUNT_OF_VALUES) {
values.remove(0);
}
values.add(value);
}
/**
* 规一化y轴方向的值. 使得value在y轴的值为[0, height]之间.
*/
private int normalizeValueForYAxis(int value, int height) {
return (int) ((double) height / MAX_VALUE * value);
}
private static void createGuiAndShow() {
//窗体的名称
JFrame frame = new JFrame("java动态绘制图形");
//内容
frame.getContentPane().add(new Plaint());
//设置关闭窗体就是关闭整个程序
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗体的大小
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
//设置窗体可见
frame.setVisible(true);
}
//
// public static void main(String[] args) {
// createGuiAndShow();
// }
}
运行结果截图
由于涉及个人隐私部分图片的相关文字打上了马赛克
图片1说明:输入字符串后识别成功
图片2说明:识别成功后右边自动填写相关的属性
图片3说明:更换顺序仍旧识别成功
图片4说明:缺少属性识别失败
图片5说明:将未识别到的属性列置空,其他的照填
结语
如果有疑问欢迎大家留言讨论,你如果觉得这篇文章对你有帮助可以给我一个免费的赞吗?我们之间的交流是我最大的动力!