又快开学了。。写一个课程表当练手。先用HttpWatcher把课程爬下来存进txt里(代码省略),然后解析成每周课表,就像超级课程表一样。爬虫的结果如下:

最终效果如下:

代码如下:

// Coding starts here
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileNameExtensionFilter;/*** GUI主窗口。显示课程表主体* 最后一次修改时间:Feb. 22nd, 2019* @author Hippo* @since Feb. 16th, 2019*/
public class ScheduleTableGUI extends JFrame
{private static final long serialVersionUID = -3144698016849055495L;private JPanel contentPane;private JLabel[] labels;private JComboBox<String> comboBox;private static String title = "河马课程表 - null";/*** Launch the application.*/public static void main(String[] args){EventQueue.invokeLater(() ->{try{UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}catch (Exception whatever) // There's nothing (I could / to) do, sorry.{}try{ScheduleUtilities.readCurricula(Paths.get("./src/justdowhateveryouwant/curricula.txt"));ScheduleTableGUI frame = new ScheduleTableGUI();frame.setVisible(true);}catch (Exception e){e.printStackTrace();String method = "set";if (e instanceof IOException)method = "read";JOptionPane.showMessageDialog(null,method + "Curricula() method failed. More information:\r\n" + e.getClass().getName() + ": " + e.getMessage(),"河马课程表", JOptionPane.ERROR_MESSAGE);}});}/*** Create the frame.*/public ScheduleTableGUI(){setTitle(title);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setBounds(100, 100, 1336, 819);setResizable(false);contentPane = new JPanel();contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));contentPane.setLayout(new BorderLayout(0, 0));setContentPane(contentPane);JPanel northFlowPanel = new JPanel(new FlowLayout());contentPane.add(northFlowPanel, BorderLayout.NORTH);JPanel centerNullPanel = new JPanel(null);centerNullPanel.setBorder(new EmptyBorder(5, 5, 5, 5));contentPane.add(centerNullPanel, BorderLayout.CENTER);Color darkerGray = Color.GRAY.darker();Color ligherBlack = darkerGray.darker().darker().darker();labels = new JLabel[48];for (int i = 0; i < 6; i++){for (int j = 0; j < 8; j++){int index = i * 8 + j;labels[index] = new JLabel();labels[index].setBounds(j * 165, i * 125, 165, 125);labels[index].setOpaque(true);labels[index].setHorizontalAlignment(JTextField.CENTER);if ((i & 1) == 0)labels[index].setBackground((j & 1) == 0 ? ligherBlack : darkerGray);elselabels[index].setBackground((j & 1) == 0 ? darkerGray : ligherBlack);labels[index].setForeground(Color.WHITE);centerNullPanel.add(labels[index]);}}{// BLOCK ALERT: Should never be modified unless regulations changedlabels[0].setText("<html><body><h1>河马课程表</h1></body></html>");ScheduleUtilities.setWeekLabels(labels, 1);labels[8].setText("<html><body><h2>第1-2节<br /></h2>上午</body></html>");labels[16].setText("<html><body><h2>第3-4节<br /></h2>上午</body></html>");labels[24].setText("<html><body><h2>第5-6节<br /></h2>下午</body></html>");labels[32].setText("<html><body><h2>第7-8节<br /></h2>下午</body></html>");labels[40].setText("<html><body><h2>第9-10节<br /></h2>晚上</body></html>");}comboBox = new JComboBox<>();comboBox.addActionListener(event ->{int week = comboBox.getSelectedIndex() + 1;ScheduleUtilities.setCurricula(week, labels);ScheduleUtilities.setWeekLabels(labels, week);setTitle(title);});comboBox.setSize(330, 30);for (int i = 1; i < 23; i++)comboBox.addItem(String.format("    第 %2d 周    ", i));northFlowPanel.add(comboBox);JButton sttstcsBtn = new JButton("数据统计");sttstcsBtn.addActionListener(event -> {String statistics = ScheduleUtilities.statistics();String[] buttons = { "     确定     ", "     导出     ", "     取消     " };if (JOptionPane.showOptionDialog(null, statistics, "河马课程表", 0, 1, null, buttons, buttons[0]) == 1){JFileChooser chooser = new JFileChooser(".");chooser.setAcceptAllFileFilterUsed(false);chooser.setFileFilter(new FileNameExtensionFilter("文本文件(*.txt)", "txt"));chooser.showOpenDialog(this);String saveTo = chooser.getSelectedFile().getAbsolutePath();if (!saveTo.endsWith(".txt"))saveTo += ".txt";try (PrintWriter pw = new PrintWriter(saveTo)){pw.println("[河马课程表]\r\n[Statistics][导出时间:" + LocalDate.now() + " " + LocalTime.now()+ "]\r\n" + statistics);JOptionPane.showMessageDialog(null, "导出完成", "河马课程表", JOptionPane.INFORMATION_MESSAGE);}catch (IOException e){JOptionPane.showMessageDialog(null,"文件读写时出错。 More information:\r\n" + e.getClass().getName() + ": " + e.getMessage(),"河马课程表", JOptionPane.ERROR_MESSAGE);}}});northFlowPanel.add(sttstcsBtn);}public static void resetTitle(String t) { title = t; }
}/*** 课表实用类* 包含所有课程的信息集合、解析文件、设置课程等方法* @author Hippo*/
class ScheduleUtilities
{private static ArrayList<ClassInfo> infos;/*** 设置周一到周日的标签(带日期)* @param labels*/public static void setWeekLabels(JLabel[] labels, int week){LocalDate date = LocalDate.of(2018, 3, 5).plusDays((week - 1) * 7);labels[1].setText("<html><body><h2>星期一<br /></h2>" + date + "</body></html>");labels[2].setText("<html><body><h2>星期二<br /></h2>" + date.plusDays(1) + "</body></html>");labels[3].setText("<html><body><h2>星期三<br /></h2>" + date.plusDays(2) + "</body></html>");labels[4].setText("<html><body><h2>星期四<br /></h2>" + date.plusDays(3) + "</body></html>");labels[5].setText("<html><body><h2>星期五<br /></h2>" + date.plusDays(4) + "</body></html>");labels[6].setText("<html><body><h2>星期六<br /></h2>" + date.plusDays(5) + "</body></html>");labels[7].setText("<html><body><h2>星期日<br /></h2>" + date.plusDays(6) + "</body></html>");}/*** 根据{@code infos}向表格添加课程* @param week 当前周数* @param labels JLabel数组传参*/public static void setCurricula(int week, JLabel[] labels){for (int i = 9; i < 48; i++){if (i == 16 || i == 24 || i == 32 || i == 40)continue;labels[i].setText("");}ArrayList<ClassInfo> needed = getWeekInfo(week);int overlapped = 0;for (ClassInfo each : needed){int index = getIndex(each);if (labels[index].getText().equals(""))labels[index].setText(each.toScheduleString(false));else{overlapped = 4;labels[index].setText(each.toScheduleString(true));}}if (overlapped == 4)JOptionPane.showMessageDialog(null, "发现本周存在课程重叠(已标记),您无法修得所有课程!", "河马课程表", JOptionPane.ERROR_MESSAGE);}/*** 获得当前周的所有课程* @param week 当前周数* @return*/private static ArrayList<ClassInfo> getWeekInfo(int week){ArrayList<ClassInfo> needed = new ArrayList<>();for (ClassInfo info : infos)if (info.getWeeks().contains(week))needed.add(info);return needed;}private static ArrayList<Integer> getOddWeeks(ClassInfo info){ArrayList<Integer> weeks = new ArrayList<>();for (Integer each : info.getWeeks())if ((each & 1) == 1)weeks.add(each);return weeks;}private static ArrayList<Integer> getEvenWeeks(ClassInfo info){ArrayList<Integer> weeks = new ArrayList<>();for (Integer each : info.getWeeks())if ((each & 1) == 0)weeks.add(each);return weeks;}/*** 根据课程获取JLabel数组的角标* @param each* @return*/private static int getIndex(ClassInfo info){int weekday = info.getWeekday();int time = info.getStartTime();return (time + 1) / 2 * 8 + weekday;}/*** 根据文件解析课程* @param path 文件路径* @throws IOException*/public static void readCurricula(Path path) throws IOException{infos = new ArrayList<>();List<String> lines = Files.readAllLines(path, Charset.forName("gbk"));ScheduleTableGUI.resetTitle("河马课程表 - " + lines.get(0));int flag = 0;ClassInfo info = null;for (int i = 1; i < lines.size(); i++){String currentLine = lines.get(i);if (currentLine == null || currentLine.equals(""))  // 跳过空行continue;if (currentLine.contains("|"))  // 则该行为“课程名 | 任课教师 | 授课周数 | 学分”,flag为0{info = new ClassInfo();String[] strs = lines.get(i).split(" *\\| *");info.setName(strs[0]);info.setProfessor(strs[1]);String[] weeksStr = strs[2].replaceAll("[^0-9\\-,]", "").split(",");ArrayList<Integer> weeks = new ArrayList<>();for (String week : weeksStr){if (week.contains("-")){String[] dual = week.split("\\-");int start = Integer.parseInt(dual[0]);int end = Integer.parseInt(dual[1]);for (int k = start; k <= end; k++)weeks.add(k);}elseweeks.add(Integer.parseInt(week));}info.setWeeks(weeks);info.setCredit(Double.parseDouble(strs[3]));flag = 0;}else  // 则该行为“星期Xa-b节,地点,校区[,单双周限制]”,flag为1。假设a和b只相差1{if (flag == 1)info = ClassInfo.cloneHalf(infos.get(infos.size() - 1));String[] strs = lines.get(i).split(",");int weekday = 0;switch (strs[0].charAt(2)){case '一':default:weekday = 1;break;case '二':weekday = 2;break;case '三':weekday = 3;break;case '四':weekday = 4;break;case '五':weekday = 5;break;case '六':weekday = 6;break;case '日':weekday = 7;}info.setWeekday(weekday);info.setStartTime(Integer.parseInt("" + strs[0].charAt(3)));info.setClassroom(strs[1]);info.setCampus(strs[2]);if (strs.length == 4){if (strs[3].equals("单周"))info.setOdd(true);else if (strs[3].equals("双周"))info.setEven(true);}flag = 1;ArrayList<Integer> weeks = null;if (info.isOdd())weeks = getOddWeeks(info);else if (info.isEven())weeks = getEvenWeeks(info);elseweeks = info.getWeeks();info.setWeeks(weeks);infos.add(info);}}
//        for (ClassInfo each : infos)
//            System.out.println(each);}/*** 统计本学期课程数据*/public static String statistics(){StringBuilder sb = new StringBuilder("以下数据按照学分倒序排列:\r\n");ArrayList<ClassInfo> merged = new ArrayList<>();double totalCredit = 0;BIG_LOOP:for (int d = 0; d < infos.size(); d++){ClassInfo info = infos.get(d);info.setTotal(info.getWeeks().size());for (int i = 0; i < merged.size(); i++){ClassInfo current = merged.get(i);if (current.equals(info)){current.setTotal(current.getToTal() + info.getToTal());continue BIG_LOOP;}}merged.add(info);totalCredit += info.getCredit();}merged.sort((a, b) ->{return Double.compare(b.getCredit(), a.getCredit());});int totalClasses = 0;for (ClassInfo each : merged){sb.append(each.toStatisticalString() + "\r\n");totalClasses += each.getToTal();}sb.append("\r\n若成功活过本学期的" + totalClasses + "堂课,你将至少获得" + String.format("%.1f", totalCredit) + "学分!\r\n");return sb.toString();}
}/*** 包含每门课所有信息的课程类* @author Hippo*/
class ClassInfo
{private String name;  // 课程名称private String professor;  // 任课教师private ArrayList<Integer> weeks;  // 上课的周数private int weekday;  // 星期几上课private int startTime;  // 上课时间(取第一个序号)private String classroom;  // 上课地点private String campus;  // 校区private boolean odd = false;  // 单周上课private boolean even = false;  // 双周上课private double credit;  // 学分private int total;  // 本学期该课程总课数public String getName() { return name; }public void setName(String name) { this.name = name; }public String getProfessor() { return professor; }public void setProfessor(String professor) { this.professor = professor; }public ArrayList<Integer> getWeeks() { return weeks; }public void setWeeks(ArrayList<Integer> weeks) { this.weeks = weeks; }public int getWeekday() { return weekday; }public void setWeekday(int weekday) { this.weekday = weekday; }public int getStartTime() { return startTime; }public void setStartTime(int startTime) { this.startTime = startTime; }public String getClassroom() { return classroom; }public void setClassroom(String classroom) { this.classroom = classroom; }public String getCampus() { return campus; }public void setCampus(String campus) { this.campus = campus; }public boolean isOdd() { return odd; }public void setOdd(boolean odd) { this.odd = odd; }public boolean isEven() { return even; }public void setEven(boolean even) { this.even = even; }public double getCredit() { return credit; }public void setCredit(double credit) { this.credit = credit; }public int getToTal() { return total; }public void setTotal(int total) { this.total = total; }/*** 每门课信息不止一行时,每行都算作一门新课* 用此方法返回初始化了一半参数的新ClassInfo对象* @param info 最后一次创建的ClassInfo对象* @return 新ClassInfo对象*/public static ClassInfo cloneHalf(ClassInfo info){ClassInfo newInfo = new ClassInfo();newInfo.setName(info.getName());newInfo.setProfessor(info.getProfessor());newInfo.setWeeks(info.getWeeks());newInfo.setCredit(info.getCredit());return newInfo;}@Overridepublic String toString(){return String.format("[课程名称=%s, 任课教师=%s, 周数=%s, 星期=%d, 时间=%d, 地点=%s, 校区=%s, 单周=%b, 双周=%b,学分=%.1f]",name, professor, weeks, weekday, startTime, classroom, campus, odd, even, credit);}/*** 课程表中每个格子的格式* @param overlapped 是否存在课程重叠* @return 格式化后的字符串*/public String toScheduleString(boolean overlapped){return String.format("<html><body><center>%s<br />教师:%s<br />@ %s<br />(%s)<br />%.1f学分"+ (overlapped ? "<br /><b><font color=\"red\">课程重叠!</font></b>" : "")+ "</center></body></html>",name, professor, classroom, campus, credit);}public String toStatisticalString(){return String.format("[%.1f学分][%s] 共计%d节课,即%d个学时,%.1f个小时", credit, name, total, total * 2, total * 1.5);}/*** 若两门课的名称一致,则认为两门课相同* @return boolean*/@Overridepublic boolean equals(Object obj){if (obj == null || !(obj instanceof ClassInfo))return false;if (obj == this)return true;return getName().equals(((ClassInfo) obj).getName());}
}

在进阶的路上,欢迎各位大神指正。

Java: 将课程表解析成每周课表相关推荐

  1. 探索使用JAVA将汉字解析成拼音

    最近在做城市选择器的时候,有一个需求是需要把汉字转化成拼音,然后根据首字母进行列表排列,做网上找到了一份可用的源码,现在对其内部的原理进行解析,其中还有一两个点没完全理解,但是不妨碍对整体的理解,如果 ...

  2. java导出excel 科学计数法_基于Java将Excel科学计数法解析成数字

    需要注意的是一般的科学表达式是 1.8E12 1.8E-12 而在Excel中的科学表达式是 1.8E+12 1.8E-12 我写的科学计数法的正则表达式是 (-?\d+\.?\d*)[Ee]{1}[ ...

  3. 使用递归算法结合数据库解析成java树形结构

    使用递归算法结合数据库解析成java树形结构 1.准备表结构及对应的表数据 a.表结构: create table TB_TREE ( CID NUMBER not null, CNAME VARCH ...

  4. java 树状数据算法_使用递归算法结合数据库解析成Java树形结构的代码解析

    这篇文章主要介绍了使用递归算法结合数据库解析成Java树形结构的代码解析的相关资料,需要的朋友可以参考下 1.准备表结构及对应的表数据 a.表结构:create table TB_TREE ( CID ...

  5. java json插件安装_IDEAL葵花宝典:java代码开发规范插件:GsonFormat插件将JSONObject格式的String 解析成实体...

    前言: GsonFormat插件主要用于使用Gson库将JSONObject格式的String 解析成实体,该插件可以加快开发进度,使用非常方便,效率高. 这个教程主要是学习IntelliJ IDEA ...

  6. java 文件解析成JSON数据(其三)

    个人用途,用于将数据解析成json格式使用 import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; ...

  7. dom4j java对象_dom4j解析XML成对象

    最近不太忙,发现现在服务之间的交互都是通过xml进行的,所以今天理了一下xml的两种解析方式.首先是最流行的dom4j解析.先解析,然后通过反射转成对象. 用到的jar:dom4j-1.6.1.jar ...

  8. 新版小爱课程表正方教务系统课表适配

    新版小爱课程表正方教务系统课表适配 前言 之前写过一篇小爱课程表的教务系统适配,但是是比较老的版本开发者工具适配了,最近看到小爱课程表开发者工具更新了,就想着写一篇新的博客,顺便优化一下之前的代码,还 ...

  9. Java 面试全解析:核心知识点与典型面试题

    课程背景 又逢"金九银十",年轻的毕业生们满怀希望与忐忑,去寻找.竞争一个工作机会.已经在职的开发同学,也想通过社会招聘或者内推的时机争取到更好的待遇.更大的平台. 然而,面试人群 ...

最新文章

  1. svn提示服务器禁止修改目录,SVN Eclipse插件中如何忽略对服务器已有文件修改后的提交...
  2. 022_JavaScript数字
  3. Deep Metric Learning for Person Re-Identification
  4. 【CentOS 7笔记24】,实验中发生的磁盘小故障#
  5. 牛客题霸 NC27 集合的所有子集
  6. 我是如何学习写一个操作系统(九):文件系统
  7. 【ArcGIS遇上Python】ArcGIS Python批处理入门到精通实用教程目录
  8. 解决:Docker 启动的容器内部时间比服务器时间晚 8 小时,容器内部时间与宿主机时间不一致
  9. html的canvas显示数字,HTML5效果:Canvas 实现圆形进度条并显示数字百分比
  10. plsql developer13的下载、instantclient的下载
  11. java equals 字符串_Java String 字符串 比较 == equals
  12. 密码库LibTomcrypt的内容介绍及分析
  13. 服务器硬盘数据备份到nas,群晖NAS教程第五节:如何备份 Synology NAS
  14. cmder 下载与简单设置
  15. python函数调用执行的四个步骤_如何调用python函数
  16. 面试中被问到:你在工作中碰到的最困难的问题是什么?
  17. [建立基类Building,作为楼房类,这个基类中包含楼房层数、房间数、楼房总面积等。再建立派生类Home_Arch、Office_Building和Hospital,分别作为住宅楼类、办公楼类和医院
  18. qpython 3h和oh_**python中的类和他的成员
  19. 魔兽世界怀旧服最新服务器开发时间,怀旧服全部服务器开放时间
  20. sin cos 信号相加计算

热门文章

  1. Java编程思想读书笔记——初始化与清理(二)
  2. 用Ubuntu编写第一个C程序并预处理、编译、汇编、链接
  3. FFMpeg打开文件报错:Invalida data found when processing input
  4. python判断素数程序_python素数判断
  5. HTML个人简历表制作
  6. 设计模式篇:状态模式(二)
  7. 计算机专业省赛一等奖有什么好处,省技能大赛一等奖好处都有什么
  8. nn.Dropout
  9. 虚拟机建立游戏服务器,在虚拟机上创建游戏服务器
  10. VO,DTO,DO,PO区别