【JAVA】仿顺丰淘宝智能识别信息模块——DidYourTypeItCorrectly

文章目录

    • 题目
    • 项目层级结构
    • 解答
      • 已完成的部分简介
      • 未完成的部分概述
      • 代码部分
        • DidYourTypeCorrectly.java
        • FormModel.java
        • IntelligentRecognition.java
        • MVCWindow.java
        • Plaint.java
    • 运行结果截图
    • 结语

题目

模拟顺风地址智能识别,对用户输入的信息,包括:姓名、地址、邮政编码、身份证号码、电话号码、电子邮箱等文本信息进行解析,并进行初步的合法性判断。

  • 基础的:文本信息放在文件,代码正确,可扩展性好(考核知识点:面向对象+正则表达式(P233、P285)+I/O+Scanner(P239))
  • 进阶的:界面友好,代码正确,可扩展性好(考核知识点:面向对象+正则表达式(P233、P285)+MVC模式(P298)+Swing+Scanner(P239))

样例视图如下

【JAVA】仿顺丰淘宝智能识别信息模块——DidYourTypeItCorrectly_第1张图片


项目层级结构


├─.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
      

解答

下面简单介绍一下这个项目已完成和未完成的地方~

已完成的部分简介

  1. 友好、黑色简约的UI
    【JAVA】仿顺丰淘宝智能识别信息模块——DidYourTypeItCorrectly_第2张图片

  2. 可扩展性较好,后续可填加别的字段如银行卡信息等

  3. 使用MVC模式构建(FormModal \ MVCWindow \ IntelligentRecognition)

  4. 代码健壮性良好。用户输入字符串不需要用空格来分割、也不需要使用字段前缀,如姓名张三地址汕头大学等。

  5. 友好的识别提示,用户点击了识别后会在右边出现一个弹框,若右边的属性全部匹配成功则会弹出“成功”否则未“失败”

未完成的部分概述

  1. 使用JavaFx来构建UI页面,JFrame太受局限了,不能在最大程度上优化页面UI
  2. 适用国家仅限中国。若输入英文名、英文的地址、别国的邮编、别国的手机号可能会出现错误。
  3. 未能完全匹配姓名(百家姓的Unicode编码不全)

代码部分

根据上面项目的层级结构一共有5个java源文件,下面将一一展示出来

DidYourTypeCorrectly.java

/*
 * @Author: hiddenSharp429 [email protected]
 * @Date: 2023-05-17 18:14:42
 * @LastEditors: hiddenSharp429 [email protected]
 * @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 [email protected]
 * @Date: 2023-05-17 18:08:09
 * @LastEditors: hiddenSharp429 [email protected]
 * @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字符串
        输入如:“张三广东省深圳市宝安区西乡街道泰华阳光海[email protected]”
        解析出姓名,地址,邮编,身份证号,电话号码,电子邮箱等信息,
        顺序可打乱,但是必须包含姓名,地址,邮编,身份证号,电话号码,电子邮箱等信息
         */
        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 [email protected]
 * @Date: 2023-05-17 18:07:27
 * @LastEditors: hiddenSharp429 [email protected]
 * @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();
//    }
}

运行结果截图

由于涉及个人隐私部分图片的相关文字打上了马赛克
【JAVA】仿顺丰淘宝智能识别信息模块——DidYourTypeItCorrectly_第3张图片
图片1说明:输入字符串后识别成功

【JAVA】仿顺丰淘宝智能识别信息模块——DidYourTypeItCorrectly_第4张图片
图片2说明:识别成功后右边自动填写相关的属性

【JAVA】仿顺丰淘宝智能识别信息模块——DidYourTypeItCorrectly_第5张图片
图片3说明:更换顺序仍旧识别成功

【JAVA】仿顺丰淘宝智能识别信息模块——DidYourTypeItCorrectly_第6张图片图片4说明:缺少属性识别失败

【JAVA】仿顺丰淘宝智能识别信息模块——DidYourTypeItCorrectly_第7张图片
图片5说明:将未识别到的属性列置空,其他的照填


结语

如果有疑问欢迎大家留言讨论,你如果觉得这篇文章对你有帮助可以给我一个免费的赞吗?我们之间的交流是我最大的动力!

你可能感兴趣的:(JAVA,java,开发语言)