2012年4月18日 星期三

師父: 那些我在課堂外學會的本事

師父 - 那些我在課堂外學會的本事


記得 n 年前聽同事分享這本書很好看,當下我就隨手跟圖書館預約了,直到 n > 1.5 年後?我終於排到這本書了 XD 不愧是熱門書,書皮都快翻爛了,我看了幾十頁就下單買了這本書。這本書其實是把常聽到的粗略小事濃縮成故事敘說出來,如果你周邊都是一群真正拿自己的錢在創業的,那或許早已聽過五四三呢。


這本書比較著重在數字的管理,算是挺善用數學的效應 :D 我覺得對一般有興趣創業的人都可以翻來筆記一下,不是多高深的技術,卻還挺有用的,應該算通用的角度跟經驗分享。如果說 「Rework 工作大解放:這樣做事反而更成功」是用來激勵人心,那「師父:那些我在課堂外學會的本事」則偏向營運管理吧 :D 我覺得這兩本都算是創業型書籍,而且不像教科書那種 xx 管理課程,必須在大公司才能展現,甚至這本書的某章節還帶到一點 Game Theory 的生活應用角度喔,就那句經典名言:尋求彼此「不滿意,但可以接受」的狀態。


這本書比較適合細細品味,偶爾翻個一兩回也挺不錯的。


[Java] 使用 Apache POI 擷取 Word、Excel、PowerPoint 文字


Apache POI - the Java API for Microsoft Documents


這次用 POI 的目的是練習把 Word、Excel 和 PowerPoint 裡頭的文字擷取出來,如果用 "extract"、"text" 和 "doc"、"docx"、"ppt" 和 "pptx" 很容易找到網路上用 Apache POI 所作的範例,此次我就拿這套來練習,那目標呢?我翻了一下 POI 的程式碼,至少要做到 doc、docx、ppt、pptx、xls、xlsx 的文字抽取,而測次結果的確都做得到了。


首先我很懶地看文字,只稍微看到官網的 Text Extraction 介紹,但那段就成為我程式的主要架構了,經過多次的旁敲側擊,讓我發現挖到寶的是 TestExtractorFactory.java!真的是太讚啦,簡單地說我想要了解 POI 跟如何去做的事,完完全全看 TestExtractorFactory.java 就搞定了!包含支援哪些檔案格式、怎樣用,全部清清楚楚,看來從 test case 開始也是另類的偷懶式學習。


最後,程式碼:


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.StringBuffer;


// https://svn.apache.org/repos/asf/poi/trunk/src/ooxml/testcases/org/apache/poi/extractor/TestExtractorFactory.java
import org.apache.poi.POIOLE2TextExtractor;
import org.apache.poi.POITextExtractor;
//import org.apache.poi.POIDataSamples;
//import org.apache.poi.extractor.*;
import org.apache.poi.extractor.ExtractorFactory;
import org.apache.poi.hdgf.extractor.VisioTextExtractor;
import org.apache.poi.hpbf.extractor.PublisherTextExtractor;
import org.apache.poi.hslf.extractor.PowerPointExtractor;
import org.apache.poi.hsmf.extractor.OutlookTextExtactor;
import org.apache.poi.hssf.extractor.EventBasedExcelExtractor;
import org.apache.poi.hssf.extractor.ExcelExtractor;
import org.apache.poi.hwpf.extractor.Word6Extractor;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.xslf.extractor.XSLFPowerPointExtractor;
import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor;
import org.apache.poi.xssf.extractor.XSSFExcelExtractor;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;


import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;


import org.apache.poi.xslf.usermodel.XMLSlideShow; // pptx 2007, http://poi.apache.org/apidocs/org/apache/poi/xslf/
import org.apache.poi.xwpf.usermodel.XWPFDocument; // docx 2007, http://poi.apache.org/apidocs/org/apache/poi/xwpf/
import org.apache.poi.xssf.usermodel.XSSFWorkbook; // xlsx 2007, http://poi.apache.org/apidocs/org/apache/poi/xssf/


class ExtractText
{
    public static String file(String path)
    {
        try { return pptx(new FileInputStream(path)); } catch(Exception e) { }
        try { return docx(new FileInputStream(path)); } catch(Exception e) { }
        try { return xlsx(new FileInputStream(path)); } catch(Exception e) { }
        return "";
    }
    public static String pptx(InputStream in) throws Exception
    {
        XSLFPowerPointExtractor o = new XSLFPowerPointExtractor( new XMLSlideShow(in) );
        o.setSlidesByDefault(true);
        o.setNotesByDefault(true);
        return o.getText();
    }
    public static String docx(InputStream in) throws Exception
    {
        XWPFWordExtractor o = new XWPFWordExtractor(new XWPFDocument(in));
        return o.getText();
    }
    public static String xlsx(InputStream in) throws Exception
    {
        XSSFExcelExtractor o = new XSSFExcelExtractor(new XSSFWorkbook(in));
        return o.getText();
    }
    public static void main(String argv[])
    {
        try
        {
            InputStream in = null;
            if( argv.length < 1 )
                in = System.in;
            else
                in = new FileInputStream(path);
            StringBuffer output = new StringBuffer();
            POITextExtractor textExtractor = ExtractorFactory.createExtractor(in);
            //POIFSFileSystem fileSystem = new POIFSFileSystem(in);
            //POITextExtractor textExtractor = ExtractorFactory.createExtractor(fileSystem);
            //POIOLE2TextExtractor oleTextExtractor = ExtractorFactory.createExtractor(fileSystem);
            //POITextExtractor[] embeddedExtractors = ExtractorFactory.getEmbededDocsTextExtractors(oleTextExtractor);
            //for (POITextExtractor textExtractor : embeddedExtractors)
            {
                if (textExtractor instanceof ExcelExtractor) // xls, excel 97-2003
                {
                    ExcelExtractor extractor = (ExcelExtractor) textExtractor;
                    //System.out.println(extractor.getText());
                    output.append(extractor.getText());
                }
                else if (textExtractor instanceof XSSFExcelExtractor) // xlsx, excel 2007
                {
                    XSSFExcelExtractor extractor = (XSSFExcelExtractor) textExtractor;
                    //System.out.println(extractor.getText());
                    output.append(extractor.getText());
                }
                else if (textExtractor instanceof Word6Extractor) // doc, word 95
                {
                    Word6Extractor extractor = (Word6Extractor) textExtractor;
                    // http://poi.apache.org/apidocs/org/apache/poi/hwpf/extractor/Word6Extractor.html
                    //for (String paragraph : extractor.getParagraphText() )
                    // System.out.println(paragraph);
                    //System.out.println(extractor.getText());
                    output.append(extractor.getText());
                }
                else if (textExtractor instanceof WordExtractor) // doc, word 97-2003
                {
                    WordExtractor extractor = (WordExtractor) textExtractor;
                    // http://poi.apache.org/apidocs/org/apache/poi/hwpf/extractor/WordExtractor.html
                    //System.out.println(extractor.getHeaderText());
                    //System.out.println(extractor.getFooterText());
                    //for (String paragraph : extractor.getParagraphText() )
                    // System.out.println(paragraph);
                    //System.out.println(extractor.getText());
                    output.append(extractor.getText());
                }
                else if (textExtractor instanceof XWPFWordExtractor) // docx, word 2007
                {
                    XWPFWordExtractor extractor = (XWPFWordExtractor) textExtractor;
                    //System.out.println(extractor.getText());
                    output.append(extractor.getText());
                }
                else if (textExtractor instanceof PowerPointExtractor) // ppt, ppt 97-2003
                {
                    PowerPointExtractor extractor = (PowerPointExtractor) textExtractor;
                    //System.out.println(extractor.getText());
                    //System.out.println(extractor.getNotes());
                    output.append(extractor.getText());
                    output.append(extractor.getNotes());
                }
                else if (textExtractor instanceof XSLFPowerPointExtractor ) // pptx, powerpoint 2007
                {
                    XSLFPowerPointExtractor extractor = (XSLFPowerPointExtractor) textExtractor;
                    extractor.setSlidesByDefault(true);
                    extractor.setNotesByDefault(true);
                    //System.out.println(extractor.getText());
                    output.append(extractor.getText());
                }
                else if (textExtractor instanceof VisioTextExtractor) // vsd, visio
                {
                    VisioTextExtractor extractor = (VisioTextExtractor) textExtractor;
                    //System.out.println(extractor.getText());
                    output.append(extractor.getText());
                }
                else if (textExtractor instanceof PublisherTextExtractor) // pub, publisher
                {
                    PublisherTextExtractor extractor = (PublisherTextExtractor) textExtractor;
                    //System.out.println(extractor.getText());
                    output.append(extractor.getText());
                }
                else if (textExtractor instanceof OutlookTextExtactor) // msg, outlook
                {
                    OutlookTextExtactor extractor = (OutlookTextExtactor) textExtractor;
                    //System.out.println(extractor.getText());
                    output.append(extractor.getText());
                }
            }
            System.out.println(output.toString().replaceAll( "[\n\t\r ]+"," "));
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            // e.printStackTrace();
            // System.out.println(e);
        }
    }
}


編譯,使用 poi-bin-3.8-20120326.zip 版本:


$ javac -Xlint:deprecation -cp .:lib-3.8/commons-logging-1.1.jar:lib-3.8/poi-3.8-20120326.jar:lib-3.8/poi-ooxml-schemas-3.8-20120326.jar:lib-3.8/dom4j-1.6.1.jar:lib-3.8/poi-examples-3.8-20120326.jar:lib-3.8/poi-scratchpad-3.8-20120326.jar:lib-3.8/junit-3.8.1.jar:lib-3.8/poi-excelant-3.8-20120326.jar:lib-3.8/stax-api-1.0.1.jar:lib-3.8/log4j-1.2.13.jar:lib-3.8/poi-ooxml-3.8-20120326.jar:lib-3.8/xmlbeans-2.3.0.jar ExtractText.java


執行,使用 poi-bin-3.8-20120326.zip 版本:


$ java -cp .:lib-3.8/commons-logging-1.1.jar:lib-3.8/poi-3.8-20120326.jar:lib-3.8/poi-ooxml-schemas-3.8-20120326.jar:lib-3.8/dom4j-1.6.1.jar:lib-3.8/poi-examples-3.8-20120326.jar:lib-3.8/poi-scratchpad-3.8-20120326.jar:lib-3.8/junit-3.8.1.jar:lib-3.8/poi-excelant-3.8-20120326.jar:lib-3.8/stax-api-1.0.1.jar:lib-3.8/log4j-1.2.13.jar:lib-3.8/poi-ooxml-3.8-20120326.jar:lib-3.8/xmlbeans-2.3.0.jar ExtractText < MyOfficeFile2003.doc


$ java -cp .:lib-3.8/commons-logging-1.1.jar:lib-3.8/poi-3.8-20120326.jar:lib-3.8/poi-ooxml-schemas-3.8-20120326.jar:lib-3.8/dom4j-1.6.1.jar:lib-3.8/poi-examples-3.8-20120326.jar:lib-3.8/poi-scratchpad-3.8-20120326.jar:lib-3.8/junit-3.8.1.jar:lib-3.8/poi-excelant-3.8-20120326.jar:lib-3.8/stax-api-1.0.1.jar:lib-3.8/log4j-1.2.13.jar:lib-3.8/poi-ooxml-3.8-20120326.jar:lib-3.8/xmlbeans-2.3.0.jar ExtractText < MyOfficeFile2003.xls


$ java -cp .:lib-3.8/commons-logging-1.1.jar:lib-3.8/poi-3.8-20120326.jar:lib-3.8/poi-ooxml-schemas-3.8-20120326.jar:lib-3.8/dom4j-1.6.1.jar:lib-3.8/poi-examples-3.8-20120326.jar:lib-3.8/poi-scratchpad-3.8-20120326.jar:lib-3.8/junit-3.8.1.jar:lib-3.8/poi-excelant-3.8-20120326.jar:lib-3.8/stax-api-1.0.1.jar:lib-3.8/log4j-1.2.13.jar:lib-3.8/poi-ooxml-3.8-20120326.jar:lib-3.8/xmlbeans-2.3.0.jar ExtractText < MyOfficeFile2003.ppt


$ java -cp .:lib-3.8/commons-logging-1.1.jar:lib-3.8/poi-3.8-20120326.jar:lib-3.8/poi-ooxml-schemas-3.8-20120326.jar:lib-3.8/dom4j-1.6.1.jar:lib-3.8/poi-examples-3.8-20120326.jar:lib-3.8/poi-scratchpad-3.8-20120326.jar:lib-3.8/junit-3.8.1.jar:lib-3.8/poi-excelant-3.8-20120326.jar:lib-3.8/stax-api-1.0.1.jar:lib-3.8/log4j-1.2.13.jar:lib-3.8/poi-ooxml-3.8-20120326.jar:lib-3.8/xmlbeans-2.3.0.jar ExtractText < MyOfficeFile2007.docx


$ java -cp .:lib-3.8/commons-logging-1.1.jar:lib-3.8/poi-3.8-20120326.jar:lib-3.8/poi-ooxml-schemas-3.8-20120326.jar:lib-3.8/dom4j-1.6.1.jar:lib-3.8/poi-examples-3.8-20120326.jar:lib-3.8/poi-scratchpad-3.8-20120326.jar:lib-3.8/junit-3.8.1.jar:lib-3.8/poi-excelant-3.8-20120326.jar:lib-3.8/stax-api-1.0.1.jar:lib-3.8/log4j-1.2.13.jar:lib-3.8/poi-ooxml-3.8-20120326.jar:lib-3.8/xmlbeans-2.3.0.jar ExtractText < MyOfficeFile2007.xlsx


$ java -cp .:lib-3.8/commons-logging-1.1.jar:lib-3.8/poi-3.8-20120326.jar:lib-3.8/poi-ooxml-schemas-3.8-20120326.jar:lib-3.8/dom4j-1.6.1.jar:lib-3.8/poi-examples-3.8-20120326.jar:lib-3.8/poi-scratchpad-3.8-20120326.jar:lib-3.8/junit-3.8.1.jar:lib-3.8/poi-excelant-3.8-20120326.jar:lib-3.8/stax-api-1.0.1.jar:lib-3.8/log4j-1.2.13.jar:lib-3.8/poi-ooxml-3.8-20120326.jar:lib-3.8/xmlbeans-2.3.0.jar ExtractText < MyOfficeFile2007.pptx


只能說這軟體架構不錯,僅須稍微修改就能弄成自動判斷格式囉 :D 在此開發的環境是 Ubuntu ,因此在 -cp 參數的數值,多個 jar 檔是用冒號 ":" 分隔的,若是 Windows 的話,要改成對應的(不確定是不是分號 ";")


2012年4月12日 星期四

[iOS] 安裝 gcc、libgcc 和 header files @ iPad 5.0.1

有一陣子沒有玩 iOS 的東西,因為一些需求想要在 iOS 裡觀察系統變化,所以寫了一隻簡單的 C 程式,好不容易搞出個 gcc 後,編譯時會顯示 header file not found 的資訊,連 stdio.h 都找不到。所幸,網路上還滿多人把玩 nodejs on iPhone 的,不一會兒就找到解答啦 :D 順道筆記一下。以上的行為都是要 jailbreak 後才能進行的。


安裝 gcc:


在 Cydia 裡頭可以找到 gcc,但安裝時卻說需要 libgcc 才能進行,網路上有一些別人編好的 libgcc ,在此使用 http://apt.saurik.com/debs/ 裡頭的 libgcc_4.2-20080410-1-6_iphoneos-arm.deb,其中 saurik.com 正是 Cydia 開發及維護者,既然 jb 都建立在 Cydia 上頭,就沒啥好懷疑資安了 XD


@ iOS 系統
# cd /tmp
# wget http://apt.saurik.com/debs/libgcc_4.2-20080410-1-6_iphoneos-arm.deb
# dpkg -i libgcc_4.2-20080410-1-6_iphoneos-arm.deb


安裝完 libgcc 後,就可以在 Cydia 上頭順利安裝 gcc 囉


還有其他安裝法,可以參考:http://code.google.com/p/iphone-gcc/wiki/Installing


安裝相關 header files:


參考 How To: Set up GCC on iOS 4 的一些步驟,首先要在 iOS 裡頭安裝 rsync ,直接用 Cydia 安裝即可(我也順便安裝了 wget、vim 和 screen),接著,由於現有的 Mac OSX 環境是 Mac OSX 10.6 與 Xcode 4.2 (Build 4C199),裡頭用的是 iOS 5 SDK,因此採用的指令:


@ Mac OSX 10.6 + Xcode 4.2
> rsync -avz --ignore-existing -e ssh /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/usr/lib/ root@Your_Device_IP:/usr/lib
> rsync -avz --ignore-existing -e ssh /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/usr/include/ root@Your_Device_IP:/usr/include
> rsync -avz --ignore-existing -e ssh /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/PrivateFrameworks/ root@Your_Device_IP:/System/Library/PrivateFrameworks/
> rsync -avz --ignore-existing -e ssh /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/ root@Your_Device_IP:/System/Library/Frameworks/
> scp /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/usr/include/crt_externs.h root@Your_Device_IP:/usr/include/crt_externs.h


如此一來,就可以有對應的系統 header files 啦,雖然編譯時會顯示一堆 ld warning: bad symbol version,但對我而言剛好不影響程式的執行,就不管他了 XD 終於,我可以寫 C 了!!


2012年4月11日 星期三

[MySQL] SUBSTRING_INDEX 字串處理函式

最近因工作開始使用 MySQL ,才發現 MySQL 有內建非常豐富的函式,此例以 SUBSTRING_INDEX 作為代表。更多 String Functions 請參考 http://dev.mysql.com/doc/refman/5.0/en/string-functions.html


mysql> desc Test;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| Name | varchar(50) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
1 row in set (0.00 sec)

mysql> INSERT INTO `Test` (`Name`) VALUES ('A-1'),('A-2'),('A-3'),('B-1'),('B-2'),('C-1');
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0

mysql> SELECT * FROM `Test`;
+------+
| Name |
+------+
| A-1 |
| A-2 |
| A-3 |
| B-1 |
| B-2 |
| C-1 |
+------+
6 rows in set (0.00 sec)

mysql> SELECT SUBSTRING_INDEX(`Name`,'-',1) AS `TopItem` FROM `Test` GROUP BY `TopItem`;
+---------+
| TopItem |
+---------+
| A |
| B |
| C |
+---------+
3 rows in set (0.00 sec)


mysql> SELECT SUBSTRING_INDEX(`Name`,'-',-1) AS `SubItem` FROM `Test` GROUP BY `SubItem`;
+---------+
| SubItem |
+---------+
| 1 |
| 2 |
| 3 |
+---------+
3 rows in set (0.00 sec)

mysql> SELECT SUBSTRING_INDEX(`Name`,'-',-1) AS `BSubItem` FROM `Test` WHERE SUBSTRING_INDEX(`Name`,'-',1) = 'B';
+----------+
| BSubItem |
+----------+
| 1 |
| 2 |
+----------+
2 rows in set (0.00 sec)


2012年4月10日 星期二

遇見未來


這幾年看了幾齣七喜的廣告,還真不賴 XD 回想起來,台灣的廣告似乎只剩下一些"保險業"的廣告,也是用這一類觸動人心的角度。