Java: 将课程表解析成每周课表
生活随笔
收集整理的這篇文章主要介紹了
Java: 将课程表解析成每周课表
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
又快開學(xué)了。。寫一個(gè)課程表當(dāng)練手。先用HttpWatcher把課程爬下來存進(jìn)txt里(代碼省略),然后解析成每周課表,就像超級(jí)課程表一樣。爬蟲的結(jié)果如下:
?
最終效果如下:
?
代碼如下:
// 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主窗口。顯示課程表主體* 最后一次修改時(shí)間: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節(jié)<br /></h2>上午</body></html>");labels[16].setText("<html><body><h2>第3-4節(jié)<br /></h2>上午</body></html>");labels[24].setText("<html><body><h2>第5-6節(jié)<br /></h2>下午</body></html>");labels[32].setText("<html><body><h2>第7-8節(jié)<br /></h2>下午</body></html>");labels[40].setText("<html><body><h2>第9-10節(jié)<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("數(shù)據(jù)統(tǒng)計(jì)");sttstcsBtn.addActionListener(event -> {String statistics = ScheduleUtilities.statistics();String[] buttons = { " 確定 ", " 導(dǎo)出 ", " 取消 " };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][導(dǎo)出時(shí)間:" + LocalDate.now() + " " + LocalTime.now()+ "]\r\n" + statistics);JOptionPane.showMessageDialog(null, "導(dǎo)出完成", "河馬課程表", JOptionPane.INFORMATION_MESSAGE);}catch (IOException e){JOptionPane.showMessageDialog(null,"文件讀寫時(shí)出錯(cuò)。 More information:\r\n" + e.getClass().getName() + ": " + e.getMessage(),"河馬課程表", JOptionPane.ERROR_MESSAGE);}}});northFlowPanel.add(sttstcsBtn);}public static void resetTitle(String t) { title = t; } }/*** 課表實(shí)用類* 包含所有課程的信息集合、解析文件、設(shè)置課程等方法* @author Hippo*/ class ScheduleUtilities {private static ArrayList<ClassInfo> infos;/*** 設(shè)置周一到周日的標(biāo)簽(帶日期)* @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>");}/*** 根據(jù){@code infos}向表格添加課程* @param week 當(dāng)前周數(shù)* @param labels JLabel數(shù)組傳參*/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, "發(fā)現(xiàn)本周存在課程重疊(已標(biāo)記),您無法修得所有課程!", "河馬課程表", JOptionPane.ERROR_MESSAGE);}/*** 獲得當(dāng)前周的所有課程* @param week 當(dāng)前周數(shù)* @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;}/*** 根據(jù)課程獲取JLabel數(shù)組的角標(biāo)* @param each* @return*/private static int getIndex(ClassInfo info){int weekday = info.getWeekday();int time = info.getStartTime();return (time + 1) / 2 * 8 + weekday;}/*** 根據(jù)文件解析課程* @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("|")) // 則該行為“課程名 | 任課教師 | 授課周數(shù) | 學(xué)分”,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節(jié),地點(diǎn),校區(qū)[,單雙周限制]”,flag為1。假設(shè)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);}/*** 統(tǒng)計(jì)本學(xué)期課程數(shù)據(jù)*/public static String statistics(){StringBuilder sb = new StringBuilder("以下數(shù)據(jù)按照學(xué)分倒序排列:\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若成功活過本學(xué)期的" + totalClasses + "堂課,你將至少獲得" + String.format("%.1f", totalCredit) + "學(xué)分!\r\n");return sb.toString();} }/*** 包含每門課所有信息的課程類* @author Hippo*/ class ClassInfo {private String name; // 課程名稱private String professor; // 任課教師private ArrayList<Integer> weeks; // 上課的周數(shù)private int weekday; // 星期幾上課private int startTime; // 上課時(shí)間(取第一個(gè)序號(hào))private String classroom; // 上課地點(diǎn)private String campus; // 校區(qū)private boolean odd = false; // 單周上課private boolean even = false; // 雙周上課private double credit; // 學(xué)分private int total; // 本學(xué)期該課程總課數(shù)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; }/*** 每門課信息不止一行時(shí),每行都算作一門新課* 用此方法返回初始化了一半?yún)?shù)的新ClassInfo對(duì)象* @param info 最后一次創(chuàng)建的ClassInfo對(duì)象* @return 新ClassInfo對(duì)象*/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, 周數(shù)=%s, 星期=%d, 時(shí)間=%d, 地點(diǎn)=%s, 校區(qū)=%s, 單周=%b, 雙周=%b,學(xué)分=%.1f]",name, professor, weeks, weekday, startTime, classroom, campus, odd, even, credit);}/*** 課程表中每個(gè)格子的格式* @param overlapped 是否存在課程重疊* @return 格式化后的字符串*/public String toScheduleString(boolean overlapped){return String.format("<html><body><center>%s<br />教師:%s<br />@ %s<br />(%s)<br />%.1f學(xué)分"+ (overlapped ? "<br /><b><font color=\"red\">課程重疊!</font></b>" : "")+ "</center></body></html>",name, professor, classroom, campus, credit);}public String toStatisticalString(){return String.format("[%.1f學(xué)分][%s] 共計(jì)%d節(jié)課,即%d個(gè)學(xué)時(shí),%.1f個(gè)小時(shí)", credit, name, total, total * 2, total * 1.5);}/*** 若兩門課的名稱一致,則認(rèn)為兩門課相同* @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());} }在進(jìn)階的路上,歡迎各位大神指正。
總結(jié)
以上是生活随笔為你收集整理的Java: 将课程表解析成每周课表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LiveNVR流媒体服务Onvif/RT
- 下一篇: 计算机科学与探索期刊审稿周期,计算机科学