文章目录
- 题目
- 项目层级结构
- 解答
- 已完成的部分简介
- 未完成的部分概述
- 代码部分
- 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
│
└─srcDidYourTypeCorrectly.javaFormModel.javaicon.pngIntelligentRecognition.javaMVCWindow.javaPlaint.javaUI.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;}@Overridepublic 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();}@Overridepublic 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;那么一个数据就占据8pxint xDelta = w / MAX_COUNT_OF_VALUES;
//这个是集合的实时长度,肯定是小于或等于MAX_COUNT_OF_VALUESint 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说明:将未识别到的属性列置空,其他的照填
结语
如果有疑问欢迎大家留言讨论,你如果觉得这篇文章对你有帮助可以给我一个免费的赞吗?我们之间的交流是我最大的动力!