• 博客开通了,标记一个:) a new start [2007-12-29 13:53]
  • Java字符串split方法的小陷阱

    2009-07-29 17:07:57 by deepblue

    今天在写一个Java字符串切分程序时,发现切分后的计数一直有问题,调了半天才找到原因。。。

    下面先来看一个问题:有字符串str=“string split test” ,使用String类的split方法,根据空格切分后的字符串数组有多少个元素?我们可以用下面的程序来测试:

    String str = "string split test";
    String[] result = str.split(" ");
    System.out.println("Result size: " + result.length);
    for (String s : result)
    System.out.println(s);

    程序输出为:

    Result size: 3
    string
    split
    test

    嗯,和我们想的一样,原来的字符串被空格切分成了3个新的字符串。

    再来看一个问题:有字符串str=“” (空字符串),使用String类的split方法,根据空格切分后的字符串数组有多少个元素?

    还是用程序来测试:

    str = "";
    result = str.split(" ");
    System.out.println("Result size: " + result.length);
    for (String s : result)
    System.out.println(s);

    程序输出为:

    Result size: 1

    这里居然是1,而不是我之前认为的0,里面的元素是与原字符串相同的空字符串。

    仔细想想,其实是有道理的。无论原字符串的内容是什么,通过split切分后,如果原字符串中没有出现切分定界符,那么切分结果就返回以原字符串为原始的字符串数组;如果原字符串中有切分定界符,则从定界符处将原字符串断开,将生成的新字符串按顺序以数组的形式返回。

  • 中文分词与词性标注测评程序

    2009-07-21 00:53:03 by deepblue

    前几天为了测试中文分词和词性标注程序的效果,写了一个简单的测试程序,用于测试分词和词性标注结果的precision,recall和F-score。下面是测试输出:

    --------------Evaluation Result-------------

    Word Count Standard: 69953, Word Count Test: 69231, Correct Segmented: 67212
    P-Word=0.9708367638774538
    R-Word=0.9608165482538276
    F-Word=0.9658006667433038

    POS Count Standard: 69953, POS Count Test: 69231, Correct Segmented: 64159
    P-POS=0.9267380219843712
    R-POS=0.9171729589867482
    F-POS=0.9219306816875502

    测试程序附在此,需要的朋友可以直接用: 中文分词与词性标注测试程序

     

  • 不用临时变量,交换两个数的值

    2009-04-19 16:15:01 by deepblue

    有两个整型变量a,b,如何在不使用其他临时变量的情况下交换a,b的值?可能这个问题大家都非常熟悉了吧。

    以前我用的是这个方法:

    a=a+b;
    b=a-b;
    a=a-b;

    其实下面这种方法由于是用的位运算,因此效率更高:

    a=a^b; (1)
    b=b^a; (2)
    a=a^b; (3)

    其中,^为位运算的异或运算。证明这个结论也很简单,为了表述得清楚,我们令原始值分别为a,b,计算过程中产生的新值为a_new,b_new。

    由(1)得:a_new=a^b,即此时变量a中的值等于a_new。而(2)中,等式右边的a的值实际上已经等于a_new了,因此,由(2)得b_new=b^a_new=b^a^b。我们知道,异或运算满足交换律和结合律,因此进一步可以得到:b_new=b^a_new=b^a^b=b^b^a=0^a=a,即变量b的值变成了b_new,也就是变量a的原始值。在(3)中,等式左边变量a和b的值实际上已经等于a_new和b_new了,令等式左边的a为a_final,因此可以得到a_fianl=a_new^b_new=a^b^a=a^a^b=0^b=b,即变量a的值最终等于a_final,也就是变量b的原始值。至此,变量a,b的原始值完成了交换。

  • Catalan数

    2009-04-15 13:48:31 by deepblue

    今天才知道Catalan数这个东西。。。汗~,赶紧在网上查了资料补补课。

    令h(1)=1,catalan数满足递归式:

    h(n)= h(1)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(1) (其中n>=2)

    即:

    Catalan数递推公式

    Catalan数的通项公式为:

    Catalan数通项公式

    该公式的推导过程可以看参考资料[2]的内容,在此不再累述。

    我还看到有人争论Catalan数的通项公式应该是这样的:

    Catalan数通项公式2

    其实这两个公式本质是一样的,公式(1)是以h(1)=1为起始项,而公式(2)是以h(0)=1为起始项。

    关于Catalan数的应用可以参考这里

    这里举个应用Catalan数的例子:n个节点能组成多少种形态的二叉树?(注:每个节点相同;形态不同的左右子树对调后形成的二叉树算新的形态的二叉树)

    可以分析,当n=1时,只有1个根节点,则只能组成1种形态的二叉树,令n个节点可组成的二叉树数量表示为h(n),则h(1)=1;

    当n=2时,1个根节点固定,还有n-1个节点,可以作为左子树,也可以作为右子树,即:h(2)=h(0)*h(1)+h(1)*h(0)=2,则能组成2种形态的二叉树。这里h(0)表示空,所以只能算一种形态,即h(0)=1;

    当n=3时,1个根节点固定,还有n-1=2个节点,可以在左子树或右子树,即h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=5,则能组成5种形态的二叉树。

    以此类推,当n>=2时,可组成的二叉树数量为h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0)种,即符合Catalan数的定义,可直接利用通项公式(2)得出结果。

     

    参考资料:
    1.Catalan数,http://baike.baidu.com/view/1163998.htm
    2.Catalan数的分析和应用,http://blog.csdn.net/dlyme/archive/2008/06/10/2532831.aspx

  • 译书已出版

    2009-02-13 21:52:12 by deepblue

    去年10月份翻译的Java编程技术书籍《Java TCP/IP Socket编程(原书第2版)》已由机械工业出版社出版,详情可以点击这里,这里这里查看

    “该书内容简明扼要,条理清晰,并在讲解相应的概念或编程技巧时列举了大量的示例程序,每章附有练习,适合作为Java Socket编程的入门教程,也可供从事网络相关专业的技术人员参考。

    译者在翻译本书时尽量忠实于原文,必要时对原书中提到的概念作了一定的解释,并力求做到言简意赅,限于水平,翻译过程中难免有疏漏之处,敬请广大读者批评指正。”

    从个人角度而言,我还是更倾向于阅读英文原版书籍。那为什么还要翻译书呢?因为考虑到,毕竟还是有很大一部分人需要看中文书籍的,如果因为语言原因而不能学习到好的技术是让人遗憾的事。因此,我建议有能力阅读英文原版书籍,并有能力支付(通常原版书籍都非常昂贵)的朋友还是购买原版书进行学习,同时,也希望我翻译的这本书能够为有阅读中文书籍需求的朋友提供忠实于原著的,方便而有价值的参考。

  • NekoHtml与XPath

    2008-11-25 12:49:40 by deepblue

    今天用NekoHtml将html网页转换成DOM,再使用XPath筛选节点时,始终不能成功,结果集始终为空。找了半天原因,才发现使用XPath时,其中的tag必须是大写英文字母。示例代码如下:

    Java语言: NekoHtml+XPath
    String productsXpath = "//TABLE[@id='product-list']//DIV[1]/B/A"; // tags should be in upper case
    NodeList products;
    try {
        products = XPathAPI.selectNodeList(dom, productsXpath);
        System.out.println("found: " + products.getLength());
    }catch (TransformerException e) {
        e.printStackTrace();
    }

    注意上面代码中:String productsXpath = "//TABLE[@id='product-list']//DIV[1]/B/A";

    如果将其变成String productsXpath = "//table[@id='product-list']//div[1]/b/a"; 则无法找到期望的节点。

     

  • [转] 几个第三方 Python 库

    2008-09-25 18:17:12 by deepblue
    转自:http://blog.csdn.net/lanphaday/archive/2008/09/23/2966811.aspx

    作者:赖勇浩(http://blog.csdn.net/lanphaday)

    wxPython 如果你之前是 windows 程序员,用 MFC 或者 WIN32API 开发界面程序,那进入 Python 国度最好的 GUI 选择应该是 wxPython。它是 wxWidgets 的 Python Bind,与 wxWi...
  • 过滤XML文件中的无效字符

    2008-08-22 14:47:20 by deepblue

    最近在处理XML文件时遇到一个问题,即由于自己写程序生成的XML文件中包含了一些不可见的无效字符,导致JDom在解析该文件是抛出异常。

    这里的无效字符不是指<,>等不能出现在XML文件的标签以外的字符,也不是由于编码问题引起的乱码,而是一些超出XML合法字符范围的不可见字符。查了一下W3C中对XML 1.0的定义[1],其Unicode的合法字符范围是:

    Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
    /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */

    为了保证常用XML解析工具能将自己生成的XML文件成功解析,就需要先将文件中的无效字符过滤掉,或在生成XML文件时就对字符的有效性进行判断,抛弃无效字符。

    下面是我在网上看到的一种使用Java来过滤XML非法字符的方法[2]:

    /**
    * This method ensures that the output String has only valid XML unicode
    * characters as specified by the XML 1.0 standard. For reference, please
    * see <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the
    * standard</a>. This method will return an empty String if the input is
    * null or empty.
    *
    * @param in
    *            The String whose non-valid characters we want to remove.
    * @return The in String, stripped of non-valid characters.
    */
    public static String stripNonValidXMLCharacters(String in) {
        StringBuffer out = new StringBuffer(); // Used to hold the output.
        char current; // Used to reference the current character.

        if (in == null || ("".equals(in)))
            return ""; // vacancy test.
        for (int i = 0; i < in.length(); i++) {
            current = in.charAt(i); // NOTE: No IndexOutOfBoundsException caught
                                    // here; it should not happen.
            if ((current == 0x9) || (current == 0xA) || (current == 0xD)
                    || ((current >= 0x20) && (current <= 0xD7FF))
                    || ((current >= 0xE000) && (current <= 0xFFFD))
                    || ((current >= 0x10000) && (current <= 0x10FFFF)))
                out.append(current);
        }
        return out.toString();
    }

    实际上就是将字符串中的每个字符进行有效性判断,再将有效字符重新构建成一个新的字符串返回。

    其实,使用一些XML工具包来生成XML 文件一般都能避免写入无效字符,不过灵活性上就不如自己用程序生成了。

    另外,一直让我困惑的是,我所见到的XML工具包都是先将所有数据在内存中生成整个DOM对象,再全部写入文件,读取时也是先将整个XML文件读入内存,生成DOM对象,再进行解析。但是如果XML文件很大,内存装不下的话,这种方法岂不是不能用了?

    不知是否是因为我孤陋寡闻,没有找到好的工具,还是由于XML本来就被设计为用来存储便于网络传输的少量数据的,因而没有考虑大文件的解析方法。

    参考资料:
    [1] http://www.w3.org/TR/2000/REC-xml-20001006
    [2] http://cse-mjmcl.cse.bris.ac.uk/blog/2007/02/14/1171465494443.html