1. 简介
1.1 问题解释
我比较喜欢Google Calendar作为我显示课程的工具, 一到特定时间就会弹出通知框提醒我, 简单好用, 不像超级课程表那么多功能. 有Google Calendar这么强大的日历为什么不使用呢.
一开始我都是手工创建行程, 你需要填行程名字, 时间段, 地点... 如果是你的行程很少, 但是是会固定时间重复, 例如每周周一都要做这么一件事, 你可以使用Google Calendar的重复时间, 重复多少次, 或者到某个日期停止.
但是对于大学课程就不是那么固定啦, 如果自己创建,还要打很多字, 还要去想一下重复多少次, 假如一门课是第8周到第10周的周一上的, 你就知道要重复三次, 但还有一个问题是你要先知道第8周周一是几月几号. 如果是要把一个学期的课程添加完也要十几分钟甚至是半个小时. 而且我通常需要我现在已经上到哪一周的课
1.2 Google Calendar提供的方法
-
Google Calendar的确提供了Calendar的API, 但是我还没研究过怎么用, 以后可以考虑使用API
-
Google Calendar提供有导入日历的功能(必须在网页版才有), 是一种叫CVS格式的文件.
- 这种文件的格式就大概是说以某些符号作为分隔符来分隔数据
-
Google Calendar的帮助页面提到可以使用Google试算表(也可以使用LibreOffice的试算表, 我没试过MS Office能不能导出cvs格式的)去生成我们的行程, 就是写成这个形式, Subject是行程的名字, Start Date是行程开始日期, Start Time是开始时间, End Date是结束日期, 如果那个行程是同一天的或, Start Date和End Date要填一样的, Location是地点(我们用来保存上课地点好了, Description是描述(我用来描述我上到第几周的课),还有Private字段还有All Day字段的, 表示这个行程是不是私人的和是不是全天活动.
Kazam_screenshot_00025.png
-
Subject,Start Date,Start Time,End Date,End Time,Location,Description 半导体集成电路,02/20/2017,08:30 AM,02/20/2017,10:05 AM,教1-314,第1周
使用文本编辑器或者cat命令看一下, 原来是下面这样的格式的. 但是Google Calendar帮助页面上写着, 如果我们填写的信息是包含有逗号的, 那么应该要用双引号引起来. 例如假如你的行程名是"上课,学习", 那么你是需要使用双引号引起来. 还有要注意的是中午12点应该是12:00 PM而不是AM否则就变成凌晨了.
-
使用上面的方法是不错, 但是不可能让我手工输入, 因此下面要去寻找数据导入
2. 开工
2.1 在学校页面找数据
当我们登录进教务管理系统之后就可以查询我们的所有课程信息
Kazam_screenshot_00022.png我使用的Chrome浏览器, 可能上面操作会有点不一样
右键点击一下---选择View frame source, 就可以看到当前网页的源码
Kazam_screenshot_00026.png上面那一段就是我们想要的数据, 有课程名, 上课周数, 上课时间, 上课地点...我们先把中括号里面的内容复制到一个文件当中
2.2 数据处理
{"kcmc":"半导体集成电路","kcbh":"TMP0352","jxbmc":"电子技术14(1),电子技术14(2)","kcrwdm":"1052044","jcdm2":"01,02","zcs":"15,9,19,18,17,16,14,13,12,11,10,8,7,6,5,4,3,2,1","xq":"1","jxcdmcs":"教1-314","teaxms":"教师名"},{"kcmc":"半导体集成电路","kcbh":"TMP0352","jxbmc":"电子技术14(1),电子技术14(2)","kcrwdm":"1052044","jcdm2":"01,02","zcs":"4,5,3,2,1","xq":"3","jxcdmcs":"教2-515","teaxms":"教师名"}
一开始这一段都是一段文字, 可以先分成多行. 可以发现每一条课程记录都是用大括号括起来的{}, 如果我们把"},"换成换行符就可以变成多行了, 把上面的文字保存到一个叫source文件中
# 将},换成换行符\n
sed -i 's/},/\n/g' source
{"kcmc":"半导体集成电路","kcbh":"TMP0352","jxbmc":"电子技术14(1),电子技术14(2)","kcrwdm":"1052044","jcdm2":"01,02","zcs":"15,9,19,18,17,16,14,13,12,11,10,8,7,6,5,4,3,2,1","xq":"1","jxcdmcs":"教1-314","teaxms":"教师名"
,{"kcmc":"半导体集成电路","kcbh":"TMP0352","jxbmc":"电子技术14(1),电子技术14(2)","kcrwdm":"1052044","jcdm2":"01,02","zcs":"4,5,3,2,1","xq":"3","jxcdmcs":"教2-515","teaxms":"教师名"
现在再将一些多余的字符串去掉
# 将开头的{"kcmc":"和,{"kcmc":"去掉
sed -i 's/.*{"kcmc":"//g' source
半导体集成电路","kcbh":"TMP0352","jxbmc":"电子技术14(1),电子技术14(2)","kcrwdm":"1052044","jcdm2":"01,02","zcs":"15,9,19,18,17,16,14,13,12,11,10,8,7,6,5,4,3,2,1","xq":"1","jxcdmcs":"教1-314","teaxms":"教师名"
半导体集成电路","kcbh":"TMP0352","jxbmc":"电子技术14(1),电子技术14(2)","kcrwdm":"1052044","jcdm2":"01,02","zcs":"4,5,3,2,1","xq":"3","jxcdmcs":"教2-515","teaxms":"教师名"
然后把":"和","替换成空格
# 将":"和","替换成空格
sed -i 's/","/ /g' source
sed -i 's/":"/ /g' source
得到下面的形式
半导体集成电路 kcbh TMP0352 jxbmc 电子技术14(1),电子技术14(2) kcrwdm 1052044 jcdm2 01,02 zcs 15,9,19,18,17,16,14,13,12,11,10,8,7,6,5,4,3,2,1 xq 1 jxcdmcs 教1-314 teaxms 教师名"
半导体集成电路 kcbh TMP0352 jxbmc 电子技术14(1),电子技术14(2) kcrwdm 1052044 jcdm2 01,02 zcs 4,5,3,2,1 xq 3 jxcdmcs 教2-515 teaxms 教师名"
现在就会得到以空格分割的字段, 第一列是课程名称半导体集成电路, 第9列是上课的节数01,02, 第11列是上课的周数15,9,19,18,17,16,14,13,12,11,10,8,7,6,5,4,3,2,1, 第13列是星期几上课, 第15列是上课地点
我通常就只需要这些信息
# 使用awk命令输出我们需要的列
awk '{print $1" "$9" "$11" "$13" "$15}' source
# 命令行会输出这样的东西
半导体集成电路 01,02 15,9,19,18,17,16,14,13,12,11,10,8,7,6,5,4,3,2,1 1 教1-314
半导体集成电路 01,02 4,5,3,2,1 3 教2-515
# 使用重定向将awk的输出重定向到另外一个文件output
awk '{print $1" "$9" "$11" "$13" "$15}' source > output
现在写一个Java程序去读取这个output文件里面的内容并且装换成Google Calendar支持的CSV格式
// MyDate.java
import java.util.Calendar;
import java.util.GregorianCalendar;
public class MyDate extends GregorianCalendar {
public MyDate(int year, int month, int date){
super(year, month-1, date);
}
/**
* 添加天数
* @param day
*/
public void addDay(int day) {
add(DAY_OF_MONTH, day);
}
/**
* 将日期输出成02/21/2017的格式
*/
public String toString() {
return String.format("%02d/%02d/%04d", get(Calendar.MONTH) + 1, get(DAY_OF_MONTH), get(YEAR));
}
}
// Transfer.java
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class Transfer {
/**
* 将上课节数转换成上课时间和下课时间
* 传入的参数上课节数格式应该是
* 01,02 早上一二节上课
* 06,07 下午6,7节上课
* 05 中午第5节上课
* 10,11,12晚修上三节课
* 01,02,03,04早上连续4节课
* @param time
* @return
*/
public static String[] toCourseTime(String time) {
String[] result = new String[2];
String[] times = time.split(",");
// 如果只上一节课, 那就是中午上第五节
if (times.length == 1) {
result[0] = "1:50 PM";
result[1] = "2:30 PM";
return result;
}
// 设置上课时间
switch (times[0]) {
case "01": times[0] = "8:30 AM"; break;
case "03": times[0] = "10:25 AM"; break;
case "06": times[0] = "2:40 PM"; break;
case "08": times[0] = "4:30 PM"; break;
case "10": times[0] = "6:30 PM"; break;
}
// 设置下课时间
switch (times[times.length-1]) {
case "02": times[1] = "10:05 AM"; break;
case "04": times[1] = "12:00 PM"; break;
case "07": times[1] = "4:15 PM"; break;
case "09": times[1] = "6:00 PM"; break;
case "12": times[1] = "9:00 PM"; break;
}
// 返回结果, 上课时间保存在resuit[0], 下课时间保存在result[1]
result[0] = times[0];
result[1] = times[1];
return result;
}
/**
* 传入保存有形如下面课程信息的文件, 输出CVS格式的文件
* 课程名称 上课节数 上课周数 星期机上课 上课地点
* 例如: 高等数学 01,02 1,2,3,4,5,6 5 教1-222
* @param inputFilePath 输入文件路径
* @param outputFilePath 输出文件路径
* @param year 第一周第一天的年份
* @param month 第一周第一天的月份
* @param day 第一周第一天的日期
* @throws IOException
*/
public void transferCVS(String inputFilePath, String outputFilePath, int year, int month, int day) throws IOException {
File inputFile = new File(inputFilePath);
File outputFile = new File(outputFilePath);
if (!outputFile.exists()) {
outputFile.createNewFile();
}
PrintWriter pw = new PrintWriter(new FileWriter(outputFile, true));
BufferedReader br = new BufferedReader(new FileReader(inputFile));
String line = null;
pw.println("Subject,Start Date,Start Time,End Date,End Time,Location,Description");
while ((line = br.readLine()) != null) {
// 课程信息数组
String[] courseInfo = line.split(" ");
// 课程名字
String courseName = courseInfo[0];
// 课程上课节数
String courseTime = courseInfo[1];
// 课程上课周数
String courseWeeks = courseInfo[2];
// 课程上课周数
String[] weeks = courseWeeks.split(",");
int courseDay = Integer.parseInt(courseInfo[3]);
String coursePosition = courseInfo[4];
for (String week: weeks) {
MyDate courseDate = new MyDate(year, month, day);
int weekNum = Integer.parseInt(week);
courseDate.addDay(((weekNum-1)*7 + courseDay-1));
String[] courseTimes = toCourseTime(courseTime);
System.out.println(courseName + "," + courseDate.toString() + "," + courseTimes[0] +
"," + courseDate.toString() + "," + courseTimes[1] +
"," + coursePosition + ",第" + week + "周");
pw.println(courseName + "," + courseDate.toString() + "," + courseTimes[0] +
"," + courseDate.toString() + "," + courseTimes[1] +
"," + coursePosition + ",第" + week + "周");
}
}
pw.flush();
pw.close();
}
public static void main(String[] args) throws IOException {
Transfer transfer = new Transfer();
transfer.transferCVS("/path/to/source", "/src/com/transfer/output.cvs", 2017, 2, 20);
}
}
运行这个程序就去/path/to/目录下读取source文件, 然后转换好后在/src/com/transfer/目录下生成一个output.cvs文件, 然后导入到Google Calendar中就可以啦.
3. 导入后效果
Screenshot_20170221-131056.png Screenshot_20170221-130901.png4. 后续
我并不是太会使用Linux的工具, 也许上面根本就不需要使用到Java去写个程序, 但日后我会慢慢完善这个小程序, 让它可以操作起来更方便.
开源中国码云项目托管地址
https://git.oschina.net/kristar/CourseToCalendar.git
网友评论