图形界面其实写起来没有一点儿技术含量,但就是麻烦,需要较多的时间,加上我又没有时间,所以Lenin's Blog Writer要形成战斗力还需要一段时间。在此之前的文章就靠这个FormatDraft了。
写了有段时间了,不是什么新东西,只是最近决定不再使用Coolcode插件,而是启用更强大的IG Syntax Hilite,所以需要对程序作一些改动。程序是为方便将我写好的文本格式的文件转换成HTML格式文件而写的一个小程序,是Lenin's Blog Writer投入使用前的一个替代品,对文章的排版格式要求比较严格,所以我觉得只适合我自己,对别人没有实用意义,在此仅作观赏,不提供程序的下载了。
之所以需要将文本文件转换成HTML再复制其源码到博客,实在是迫不得已。普通的文章,几个汉字也就罢了,不过作为技术博客,文章中经常含有大量各种源代码,直接贴到博客里面容易出问题,所以只好先转换成网页格式再发布其源码了。而我写起文章容易如滔滔江水连绵不绝,这样一来如果用网页编辑器一点一点的加HTML代码的话会很累,所以写个程序来做这些事儿。
FormatDraft可以对两种格式的文章作出处理。
一种是普通格式的文件,我写文章的格式是:文件第一行是文章标题;文章标题与段落之间以及段落与段落之间用一个空行隔开;每个段落段首使用一个Tab来缩进;此外的内容以缩进宽度来表示上下段落之间的关系,即如果本段上面一段缩进了一个Tab宽度,而本段缩进了两个Tab宽度,那么本段是上面一段的子内容。
另一种是我记《Vi IMproved》的笔记时用的格式:除了普通文章中的那几条之外,使用“<>”括起来数字表示小标题;使用“()”括起来数字表示小小标题。
针对以上格式,FormatDraft做出如下处理:使用“<!-- -->”将文章标题括起来成为注释;文章标题与第一段之间的空行以“<p>”代替;段落与段落之间的空行以“</p><p>”代替;对于所有的缩进,以四个“ ”来代替每一个缩进。另外,程序会试图从“iconograph.properties”配置文件里读取插图的地址信息,并将其插入文章标题下的一行中,右对齐。vim笔记格式文件的插图地址信息定义格式为“vim=http://图片网址”,普通格式文件插图地址信息定义格式为“normal=http://图片网址”。
程序有意思的地方在于可以在文章中使用“忽略标记”,所有位于一对“忽略标记”之间的内容都不会被FormatDraft处理,而是被原封不动地输出到结果中,“忽略标记”格式为“<标记名>”或者"[标记名]"。“忽略标记”的结束标记格式为“</标记名>”或者"[/标记名]"。允许忽略标记中添加属性,即如果定义一个“忽略标记”为“<coolcode>”,那么“<coolcode>”与“</coolcode>”之间或者“<coolcode lang="java" download="sample.java">”与“</coolcode>”之间的内容都会被直接输送到作为结果的网页文件中。“忽略标记”在程序所在目录下的“EscapeMarkers.properties”文件中定义,格式为“<标记名>=</标记名>”或者"[标记名]=[/标记名]"。
文章中所有的“&”、“<”、“>”和英文双引号会被替换成HTML实体,分别为“&”“<”“>”和“"”,位于“忽略标记”内的内容不会被替换。
在vim模式中,小标题会被“<b></b>”括起来,即加粗;不包含中括号的小小标题会被“<i></i>”括起来,即斜体。
最后,使用“-normal”的参数使程序把文件以普通模式处理,使用“-vim”使程序把文件当作我的vim笔记格式的文件来处理。模式参数后可以跟一个或两个编码方案的名称作参数,缺省以UTF-8编码处理文件。命令格式为:
//什么参数都不加,直接添加文本文件的路径,以普通模式处理文件,以UTF-8解码文本文件,以UTF-8编码HTML文件
java FormatDraft /home/lenin/drafts/sample.txt//添加一个模式参数,以该模式处理该文本文件,以UTF-8解码文本文件,以UTF-8编码HTML文件
java FormatDraft -vim /home/lenin/drafts/sample.txt//添加一个模式参数和一个编码参数,以该模式处理该文本文件,以该编码解码文本文件,以UTF-8编码HTML文件
java FormatDraft -vim gbk /home/lenin/drafts/sample.txt//添加一个模式参数和两个编码参数,以该模式处理该文本文件,以第一个编码解码文本文件,以第二个编码编码HTML文件
java FormatDraft -vim utf-8 gbk /home/lenin/drafts/sample.txt
-
/*
-
* 两种模式转换文章到网页格式:
-
*
-
* 两种模式共有的处理方式:
-
* 文件第一行为标题,标题与段落之间、段落与段落之间用空行隔开
-
* 从配置文件“iconograph.properties”中读取针对该类文章的插图地址并添加到文章标题下,如果地址错误或不存在,返回零长度串
-
* 从配置文件“EscapeMarkers.properties”中读取的“忽略标记”之间的内容都会原封不动地输出到结果文件中
-
* 此外的内容以行的缩进深度来标识内容之间的关系。
-
* 转换后保存在原文本文件所在的目录,与文本文件同名,后缀是“.html”
-
* 命令格式:
-
* Linux :
-
* java FormatDraft -ARGUMENT /home/lenin/drafts/sample.txt
-
* Windows :
-
* java FormatDraft -ARGUMENT c:\drafts\sample.txt
-
*
-
* 第一种转换我的普通文章格式的文本文件到网页格式:
-
* 参数为:-normal
-
*
-
* 第二种转换我的Vi IMproved笔记格式的文本文件到网页格式:
-
* 参数为:-vim
-
* 小标题为以方括号括起来的数字,小小标题为以圆括号括起来的数字
-
*
-
*/
-
-
import java.io.File;
-
import java.io.FileInputStream;
-
import java.io.BufferedReader;
-
import java.io.PrintWriter;
-
import java.io.InputStreamReader;
-
import java.io.IOException;
-
import java.util.Properties;
-
import java.util.Set;
-
import java.util.HashSet;
-
import java.util.Enumeration;
-
-
public class FormatDraft
-
{
-
private boolean title = true; //标识当前读入行是否是文章标题
-
private boolean theFirstNullLine = true; //标识当前读入的空行是否是文章标题下的第一个空行
-
-
//转换Vim笔记格式文件的方法
-
if(!sourceFile.exists()){
-
}
-
if(!sourceFile.getName().toLowerCase().endsWith(".txt")){
-
}
-
-
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile),decoder));
-
while((temp=br.readLine())!=null){
-
//若该行为“<...>”或"[...]"格式且成功读入“忽略标记”的配置文件且该行属于“忽略标记”,则将其暂存到unclosedEscapeMarker中
-
if((temp.trim().matches("^\\<[^/\\<\\>\\[\\]]*\\>$") || temp.trim().matches("^\\[[^/\\<\\>\\[\\]]*\\]$")) && escapeMarkers.size()>0 && escapeMarkers.contains(peeler(temp))){
-
unclosedEscapeMarker = peeler(temp);
-
//否则,如果该行为“</...>”或"[/...]"格式,且成功读入“忽略标记”的配置文件,且unclosedEscapeMarker中已存有“忽略标记”,且该行与已暂存的“忽略标记”匹配,则清空unclosedEscapeMarker,并保存该行到sb,之后跳出本次循环
-
}else if((temp.trim().matches("^\\</.*\\>$") || temp.trim().matches("^\\[/.*\\]$")) && escapeMarkers.size()>0 && unclosedEscapeMarker.length()> 0 && temp.trim().equals(readClosingEscapeMarker(unclosedEscapeMarker))){
-
unclosedEscapeMarker = "";
-
sb.append(temp+"\n");
-
continue;
-
}
-
if(unclosedEscapeMarker.length() != 0){
-
sb.append(temp+"\n");
-
continue;
-
}
-
temp = temp.replaceAll("&","&"); //将“&”转换成实体
-
temp = temp.replaceAll("<","<"); //将HTML文件中的尖括号替换为实体
-
temp = temp.replaceAll(">",">");
-
temp = temp.replaceAll("\"","""); //将“"”转换成实体
-
if(title == true){
-
sb.append("<!--"+temp+"-->\n"); //将文章标题用注释括起来
-
sb.append(readIconographURL("vim","right")); //文章标题下添加插图
-
title = false;
-
}else if(temp.matches("^\\t*$")){
-
if(theFirstNullLine == true){
-
sb.append("<p>"); //如果是文章标题下的第一个空行,只添加一个分段符
-
theFirstNullLine = false;
-
}else{
-
sb.append("</p><p>"); //如果是普通空行,添加一个分段结束符和一个分段符
-
}
-
}else if(temp.matches("^\\<.*$")){
-
sb.append("<b>"+temp.trim()+"</b><br>\n"); //如果是尖括号开头的小标题行,使之加粗
-
}else if(temp.matches("^\\t*\\(.*$")){
-
if(!temp.matches("^.*\\[.*\\].*$"))
-
sb.append(TABWIDTH+"<i>"+temp.trim()+"</i><br>\n"); //如果是小括号开头的标题,且其中没有方括号括起来的命令,去掉行两端空白字符,缩进四个空格的宽度,使用斜体表示
-
else
-
sb.append(TABWIDTH+temp.trim()+"<br>\n"); //如果有方括号,使用普通字体
-
}else if(temp.matches("^\\t\\S.*$")){
-
sb.append(TABWIDTH+temp.trim()+"<br>\n"); //此外,如果以上条件都不满足,那么如果行开头有一个空白字符,则缩进四个空格
-
}else if(temp.matches("^\\t{2}\\S.*$")){
-
sb.append(TABWIDTH+TABWIDTH+temp.trim()+"<br>\n"); //如果行开头有两个空白字符,则缩进八个空格宽度
-
}else if(temp.matches("^\\t{3}\\S.*$")){
-
sb.append(TABWIDTH+TABWIDTH+TABWIDTH+temp.trim()+"<br>\n"); //如果行开头有三个空白字符,则缩进十二的空格宽度
-
}else if(temp.matches("^\\t{4}\\S.*$")){
-
sb.append(TABWIDTH+TABWIDTH+TABWIDTH+TABWIDTH+temp.trim()+"<br>\n"); //如果行开头有四个空白字符,则缩进十六的空格宽度
-
}else if(temp.matches("^\\t{5}\\S.*$")){
-
sb.append(TABWIDTH+TABWIDTH+TABWIDTH+TABWIDTH+TABWIDTH+temp.trim()+"<br>\n"); //如果行开头有五个空白字符,则缩进二十个空格宽度
-
}else{
-
}
-
}
-
sb.append("</p>");
-
-
outputFileName.append(sourceFile.getPath().substring(0,sourceFile.getPath().toLowerCase().lastIndexOf(".txt"))).append(".html"); //将原文本文件的名字中的“.txt”后缀去掉,换成“.html”
-
if(outputFile.exists())
-
outputFile.delete();
-
pw.println(sb.toString());
-
pw.flush();
-
pw.close();
-
}
-
-
//转换普通格式文件方法
-
if(!sourceFile.exists()){
-
}
-
if(!sourceFile.getName().toLowerCase().endsWith(".txt")){
-
}
-
-
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile),decoder));
-
while((temp=br.readLine())!=null){
-
//若该行为“<...>”或"[...]"格式且成功读入“忽略标记”的配置文件且该行属于“忽略标记”,则将其暂存到unclosedEscapeMarker中
-
if((temp.trim().matches("^\\<[^/\\<\\>\\[\\]]*\\>$") || temp.trim().matches("^\\[[^/\\<\\>\\[\\]]*\\]$")) && escapeMarkers.size()>0 && escapeMarkers.contains(peeler(temp))){
-
unclosedEscapeMarker = peeler(temp);
-
//否则,如果该行为“</...>”或"[/...]"格式,且成功读入“忽略标记”的配置文件,且unclosedEscapeMarker中已存有“忽略标记”,且该行与已暂存的“忽略标记”匹配,则清空unclosedEscapeMarker,并保存该行到sb,之后跳出本次循环
-
}else if((temp.trim().matches("^\\</.*\\>$") || temp.trim().matches("^\\[/.*\\]$")) && escapeMarkers.size()>0 && unclosedEscapeMarker.length()> 0 && temp.trim().equals(readClosingEscapeMarker(unclosedEscapeMarker))){
-
unclosedEscapeMarker = "";
-
sb.append(temp+"\n");
-
continue;
-
}
-
//如果还没有找到“忽略标记”的结束标记,则对当前行不处理,并将其添加到sb中
-
if(unclosedEscapeMarker.length() != 0){
-
sb.append(temp+"\n");
-
continue;
-
}
-
temp = temp.replaceAll("&","&"); //将“&”转换成实体
-
temp = temp.replaceAll("<","<"); //将HTML文件中的尖括号替换为实体
-
temp = temp.replaceAll(">",">");
-
temp = temp.replaceAll("\"","""); //将“"”转换成实体
-
if(title==true){
-
sb.append("<!--"+temp.trim()+"-->\n"); //将文章标题用注释括起来
-
sb.append(readIconographURL("normal","right")); //文章标题下添加插图
-
title = false;
-
}else if(temp.matches("^\\t*$")){
-
if(theFirstNullLine==true){ //如果是文章标题下的空行,……
-
sb.append("<p>\n");
-
theFirstNullLine = false;
-
}else{
-
sb.append("</p><p>\n"); //如果是普通空行,……
-
}
-
}else if(temp.matches("^\\t\\S.*$")){
-
sb.append(TABWIDTH+temp.trim()+"\n"); //此外,如果以上条件都不满足,那么如果行开头有一个空白字符,则缩进四个空格
-
}else if(temp.matches("^\\t{2}\\S.*$")){
-
sb.append(TABWIDTH+TABWIDTH+temp.trim()+"\n"); //如果行开头有两个空白字符,则缩进八个空格宽度
-
}else if(temp.matches("^\\t{3}\\S.*$")){
-
sb.append(TABWIDTH+TABWIDTH+TABWIDTH+temp.trim()+"\n"); //如果行开头有三个空白字符,则缩进十二的空格宽度
-
}else if(temp.matches("^\\t{4}\\S.*$")){
-
sb.append(TABWIDTH+TABWIDTH+TABWIDTH+TABWIDTH+temp.trim()+"\n"); //如果行开头有四个空白字符,则缩进十六的空格宽度
-
}else if(temp.matches("^\\t{5}\\S.*$")){
-
sb.append(TABWIDTH+TABWIDTH+TABWIDTH+TABWIDTH+TABWIDTH+temp.trim()+"\n"); //如果行开头有五个空白字符,则缩进二十个空格宽度
-
}else{
-
sb.append(temp.trim()+"\n");
-
}
-
}
-
sb.append("</p>");
-
-
outputFileName.append(sourceFile.getPath().substring(0,sourceFile.getPath().toLowerCase().lastIndexOf(".txt"))).append(".html"); //将原文本文件的名字中的“.txt”后缀去掉,换成“.html”
-
if(outputFile.exists())
-
outputFile.delete();
-
pw.println(sb.toString());
-
pw.flush();
-
pw.close();
-
}
-
-
//文章中的“忽略标记”可能有两种形式:其一直接就是配置文件中定义的格式,如“<coolcode>”;
-
//也可以是有属性的,如“<coolcode lang="java" download="sample.java">”。
-
//两种格式通过本方法一律还原成配置文件中的格式,然后返回。
-
int i = escapeMarker.trim().indexOf(" ");
-
if(i> 0){
-
if(escapeMarker.trim().matches("^\\<.*$"))
-
return escapeMarker.trim().substring(0,i)+">";
-
if(escapeMarker.trim().matches("^\\[.*$"))
-
return escapeMarker.trim().substring(0,i)+"]";
-
}
-
return escapeMarker.trim();
-
}
-
-
//从配置文件中读取“忽略标记”到escapeMarkers集合中
-
if(!initFile.exists())
-
return -1;
-
while(e.hasMoreElements()){
-
escapeMarkers.add(e.nextElement());
-
}
-
return escapeMarkers.size();
-
}
-
-
// 从配置文件读取"忽略标记"的结束标记
-
if(!initFile.exists())
-
return null;
-
return ppt.getProperty(unclosedEscapeMarker);
-
}
-
-
//从iconograph.properties文件中读出插图URL
-
if(!iconograph.exists())
-
return "";
-
if(url == null)
-
return "";
-
if(url.trim().matches("^http://.*$"))
-
return "<img src=\""+url.trim()+"\" align=\""+align+"\">\n";
-
else
-
return "";
-
}
-
-
//将help.txt文件中的内容打印出来
-
if(!helpFile.exists())
-
else{
-
String temp;
-
while((temp=br.readLine())!=null){
-
}
-
}
-
}
-
-
//打印版本信息
-
private void printVersionMsg(){
-
}
-
-
{
-
FormatDraft fd = new FormatDraft();
-
fd.readEscapeMarkers();
-
if(args.length <1){
-
}
-
//程序后面直接跟文本文件的路径,把该文本文件当普通格式处理,以UTF-8解码文本文件,以UTF-8编码HTML文件
-
if(args.length == 1){
-
if(args[0].equals("-v") || args[0].equals("-version"))
-
fd.printVersionMsg();
-
else if(args[0].equals("-h") || args[0].equals("-help"))
-
fd.printHelpMsg();
-
else fd.transformNormalDraft(args[0],"utf-8","utf-8");
-
}
-
//命令格式:java FormatDraft -vim /home/lenin/sample.txt
-
//默认以UTF-8解码和编码
-
if(args.length == 2){
-
if(args[0].equals("-vim"))
-
fd.transformVimDraft(args[1],"utf-8","utf-8");
-
else if(args[0].equals("-normal"))
-
fd.transformNormalDraft(args[1],"utf-8","utf-8");
-
else{
-
}
-
}
-
//命令格式:java FormatDraft -vim gbk /home/lenin/sample.txt
-
//第二个参数即解码文本文件时使用的编码方案,默认以utf-8格式编码转换结果
-
if(args.length == 3){
-
if(args[0].equals("-vim"))
-
fd.transformVimDraft(args[2],args[1],"utf-8");
-
else if(args[0].equals("-normal"))
-
fd.transformNormalDraft(args[2],args[1],"utf-8");
-
else{
-
}
-
}
-
//命令格式:java FormatDraft -normal gbk utf-8 /home/lenin/sample.txt
-
//第二个参数是解码文本文件时使用的编码方案,第三个参数是编码转换结果时用的编码方案
-
if(args.length == 4){
-
if(args[0].equals("-vim"))
-
fd.transformVimDraft(args[3],args[2],args[1]);
-
else if(args[0].equals("-normal"))
-
fd.transformNormalDraft(args[3],args[2],args[1]);
-
else{
-
}
-
}
-
if(args.length> 4){
-
}
-
}
-
}
下面即为“忽略标记”在配置文件"EscapeMarkers.properties"中的定义格式:
-
<coolcode>=</coolcode>
-
[java]=[/java]
-
[cpp]=[/cpp]
-
[c]=[/c]
-
[python]=[/python]
-
[php]=[/php]
下面是文章插图地址信息在配置文件"iconograph.properties"中的定义格式:
-
vim=http://sinolog.it/images/the-mug-of-vi.jpg
-
normal=http://photo15.yupoo.com/20071222/205558_725945963_m.jpg
[...] 后来我写了一个转换普通文本到HTML文档的程序,只要使用特定的格式写文章,然后使用该程序就可以自动在相应位置插入适当的HTML标记。这简化了工作量,我终于可以只关心文章内容而又不用担心文章的排版了。但是,该程序只能识别几种简单的布局格式,如果要在文章中加入其它的元素,就必须加入新的布局并在程序中加入新的代码段…… [...]