博客

  • android游戏开发框架libgdx的使用(二十一)—使用TTF字库支持中文

    android游戏开发框架libgdx的使用(二十一)—使用TTF字库支持中文

    好久没有更新这个系列的文章了。今天下午在群上讨论libgdx对中文的支持问题。本来Hiero做是最好的,但是LIbgdx的BitmapFont不支持多图,常用汉字3500个,是在做不到一张图上。

    libgdx很早之前就有ttf的支持了,不过那个时候有点问题。经测试新版本(0.96)完全支持,特地总结出来和大家分享。

    TTF字库

    TTF(TrueTypeFont)是Apple公司和Microsoft公司共同推出的字体文件格式,随着windows的流行,已经变成最常用的一种字体文件表示方式,应用范围非常广。

    如果是Windows操作系统,可以从Fonts文件夹中找到很多字库。也可以从网上下载。

    我推荐YaHei.Consolas字库,看着很爽,反正我的eclipse就是用的这个字库。

    gdx-setup-ui的使用

    从libgdx下载0.96版本,可以看到文件结构如下:

    libgdx-chinese-1

    强烈运行gdx-setup-ui.jar,这一个项目初始化工具。

    运行界面如下:

    libgdx-chinese-2

    项目名字,包名什么的按情况填写。在中间的Required配置中可以直接下载最新的稳定版本和Nightly版本。不过推荐选用本地的附件。

    libgdx-chinese-3

    不用解压,直接选择zip文件,它会自动抽取需要的文件。

    我使用的Eclipse,直接Import即可。

    libgdx-chinese-4

    我只生成了桌面项目,一般可以把Android和Web的一起生成了。

    注意一下,默认的Android项目对应的SDK是15,可以根据需要更改。有时候导入的项目会有红色感叹号,添加一个assets文件夹即可。

    libgdx-chinese-5

    其中back-libgdx项目是我们的核心,一切逻辑什么的都在这里实现。back-libgdx-XXX是对应的启动而已。

    libgdx使用TTF字库

    准备一个TTF字库改名为font.ttf复制到assets文件夹。从压缩包中找到gdx-stb-truetype-natives.jar和gdx-stb-truetype.jar。其中gdx-stb-truetype-natives.jar添加到桌面项目,gdx-stb-truetype.jar添加到核心项目中去。如图:

    libgdx-chinese-6

    现在来看看最关键的方法TrueTypeFontFactory.createBitmapFont。

    我们通过它创建一个支持ttf字库的BitmapFont出来。它需要一个FileHandle和要支持的文字。当然还有一些参数,具体意义可以参考API文档。

    也就是说我们需要使用TTF字库的哪些文字必须声明出来。不过问题也不到,3500常用汉字基本可以满足要求。网上还有一个常用500字,不过那个完全不够用。

    我这里随便写几个作为演示。

    publicstaticfinal String FONT_CHARACTERS ="世界人民爱好的美好中文支持再看看";

    然后使用初始化

    font = TrueTypeFontFactory.createBitmapFont(
    Gdx.files.internal("font.ttf"), FONT_CHARACTERS,12.5f,7.5f,
    1.0f, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

    剩下的工作和使用Hiero一样的了。

    publicclass App implements ApplicationListener {
    BitmapFont font;
    SpriteBatch batch;
    publicstaticfinal String FONT_CHARACTERS ="世界人民爱好的美好中文支持再看看";
    
    @Override
    publicvoidcreate() {
    font = TrueTypeFontFactory.createBitmapFont(
    Gdx.files.internal("font.ttf"), FONT_CHARACTERS,12.5f,7.5f,
    1.0f, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    font.setColor(1f,0f,0f,1f);
    batch =new SpriteBatch();
    }
    
    @Override
    publicvoiddispose() {
    font.dispose();
    }
    
    @Override
    publicvoidrender() {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
    batch.begin();
    font.draw(batch,"中文支持",10,10);
    batch.end();
    }
    
    @Override
    publicvoidresize(int width,int height) {
    }
    
    @Override
    publicvoidpause() {
    }
    
    @Override
    publicvoidresume() {
    }
    }

    效果如下:

    libgdx-chinese-7

    在Stage中使用TTF字库原理是一样,需要修改的只有BitmapFont的实例化方法。

    写在最后

    使用TTF字库解决libgdx显示中文无疑是一种很好的选择,基本不存在显示不出文字的情况。但是TTF字库的大小一般都比较大,比如我使用的字库是13.8M..小一点的也有3M。

    对于Android应用这个大小有时候还是难以接受的。

    android系统自带的字库位于/system/fonts/中,可以使用绝对路径访问…不过不推荐就是了。

    使用Herio是一个高效(程序效率,不是开发效率)的方法,但是libgdx不支持Herio的多图。

    有文档提到了使用SpriteSheetPacker,但是我一直没有找到。google code的代码自从迁移到Github之后就没有了,不知道是移除了还是怎么的了。

  • 基础工具–Guava-Libraries学习笔记(一)

    基础工具–Guava-Libraries学习笔记(一)

    什么是Guava-Libraries?

    Guava-Libraries是google对java的一个扩展,主要涵盖集合、缓存、并发、I/O、反射等等。

    它本来是Google内部所使用的一个类库,后来整理开源出来了。这套库的设计引入了很多新的理念,研究一下可能会使你对Java这门语言有新的认识和看法。

    地址:http://code.google.com/p/guava-libraries/

    这篇短文主要是关于Guava-Libraries基础工具,内容是我参考官方wiki和自己的使用体验结合而成。

    null的使用

    null在java中是一个很特殊的东西。它可以标识一个不确定的对象,比如

    Ojbect o =null

    同时在很多个集合中它代表key不存在,也可以代表值为null。

    null使用需要给外的小心,稍不注意就会出现很多问题。当然更多的时候只是单纯的觉得null不够优雅而已。

    Guava为我们提供了一个Optional的抽象类来解决这个问题。用类Present和Absent代表值存在和不存在。

    以下是一个例子:

    Optional possible = Optional.of(5);
    if (possible.isPresent()) {
    System.out.println(possible.get());
    }
    
    Optional absentValue = Optional. absent();
    if (absentValue.isPresent())
    System.out.println(absentValue.get());
    System.out.println(absentValue.or(-1));
    System.out.println(absentValue.orNull());
    System.out.println(absentValue.asSet());

    第一种是值存在的,第二种是值不存在的。执行效果如下:

    guava-1-1

    这里说明一下isPresent()方法是判断是否有值的。or方法是非null返回Optional的值,否则返回传入值。

    orNull()方法是非null返回Optional的值,否则返回null。

    我个人觉得or方法比较常用就是了。

    条件判断

    Guava还封装了一些条件检查方法,比如判断真假、判断是否为空、判断index是否合法等等。如果判断通过,返回值本身,否则抛出错误。

    每种方法又对应了三种重载:

    1.没有错误信息

    2.有直接的错误信息

    3.带模板的错误信息

    来个小例子:

    int i = Preconditions.checkNotNull(null);
    int i2 = Preconditions.checkNotNull(null,"错误");
    int i3 = Preconditions.checkNotNull(null,"错误:%s","001");

    效果如下:

    guava-1-2

    guava-1-3

    guava-1-4

    对象的常用方法

    简单实现了Object的一些方法而已,比如toString、hashCode。

    我个人觉得equal这块用户不大,主要是toString和Compare。
    特别是ComparisonChain的使用,有种链式编程的感觉。
    例子:

    System.out.println("a equal a :" + Objects.equal("a","a"));
    System.out.println("a equal b :" + Objects.equal("a","b"));
    
    System.out.println("hascode : "
    + Objects.hashCode("one","two",3,4.0));
    
    System.out.println("Blog toString : "
    + Objects.toStringHelper("Blog").add("name","huang")
    .add("url","http://htynkn.cnblogs.com/").toString());
    
    System.out.println(ComparisonChain.start().compare(1.0,1)
    .compare("a","a").compare(1.4411,1.441).result());

    效果:

    guava-1-5

    写在最后

    Guava是google封装以后的东西,肯定经过了很多实践和测试。但是有些东西用着还是比较奇怪,感觉封装以后更混乱了。大家挑选着合适的用吧。

  • java通过jna调用科大讯飞语音云实现语音识别功能

    java通过jna调用科大讯飞语音云实现语音识别功能

    说明:写本文时还没有提供java平台的,现在官方有java平台的sdk了,可以直接使用。本文已经没有太多实际意义了。

    语音识别技术

    语音识别就是让机器通过识别和理解过程把语音信号转变为相应的文本或命令。语音识别技术主要包括特征提取技术、模式匹配准则及模型训练技术三个方面。说实话其中的技术比较多,要独立开发新的基本上不现实。所以自然把目光放到开源项目或者其他公司的API上面了。开源项目我尝试了SpeakRight和sphinx4,但是效果都是一般。AT&T的API老是申请不上,最后把目光放在科大讯飞上了。试用了一下,效果还行,但是它提供的Windows平台的API是C/C++的,我只懂点皮毛,所以稍微研究了一下通过Java调用它的语音云SDK。

    JNA

    java调用.dll获取.so一般通过JNI,但是JNI的使用比较复杂,需要用C另写一个共享库进行适配。而JNA是一个自动适配工具,通过它调用.dll只需要一个借口即可。

    官网:https://github.com/twall/jna/

    下载jna.jar即可。

    编写接口

    科大讯飞语音云主要提供语音合成和语音识别两个方面的东西,我主要使用语音识别这块的功能。

    建立接口QTSR,继承Library。

    将msc.dll等文件复制到项目根目录。

    jna-yuyinshibie-01

    加载msc.dll

    QTSR INSTANCE = (QTSR) Native.loadLibrary("msc", QTSR.class);

    然后来看一下msc.dll公开了哪些方法。首先是QISRInit,这是一个全局初始化函数。

    jna-yuyinshibie-02

    它的返回值为int,参数是const char。int还是java的int,但是char就对应的是java的String了。

    所以在QTSR中添加方法:

    publicintQISRInit(String configs);

    返回值在msp_errors.h中定义,等一下我们还是要弄在java里面去。

    继续看QISRInit函数,在官方文档中有调用示例:

    constchar* configs=“server_url=dev.voicecloud.cn, timeout=10000, vad_enable=true”;
    
    int ret = QISRInit( configs );
    
    if(MSP_SUCCESS != ret )
    
    {
    
    printf( “QISRInit failed, error code is: %d”, ret );
    
    }

     

     

    对应的在java中的调用代码如下:

    String config ="server_url=dev.voicecloud.cn, timeout=10000, vad_enable=true";
    int code = QTSR.INSTANCE.QISRInit(config);
    if (code !=0) {
    System.out.println("QISRInit failed, error code is:" + code);
    }

    我们在看一个函数:QISRSessionBegin,这个开始一路ISR会话。

    jna-yuyinshibie-03

    还是刚才的思路,char对应java的String,但是注意一下int errorCode。这个函数其实传入两个参数,传出两个参数。即本身返回的sessionId,还有errorCode。

    这里的int*对应的是jna的IntByReference。所以添加方法:

    public StringQISRSessionBegin(String grammarList, String params,IntByReference errorCode);

     

    同样看看官方示例:

    /* vad_timeout和vad_speech_tail两个参数只有在打开VAD功能时才生效 */
    
    constchar* params=
    
    “ssm=1,sub=iat,aue=speex-wb;7,auf=audio/L16;rate=16000,ent=sms16k,rst=plain,vad_timeout=1000,vad_speech_tail=1000”;
    
    int ret = MSP_SUCCESS;
    
    constchar* session_id = QISRSessionBegin( NULL, params, &ret );
    
    if(MSP_SUCCESS != ret )
    
    {
    
    printf( “QISRSessionBegin failed, error code is: %d”, ret );
    
    }

    在java这样写:

    String params ="ssm=1,sub=iat,aue=speex-wb;7,auf=audio/L16;rate=16000,ent=sms16k,rst=plain,vad_timeout=1000,vad_speech_tail=1000";
    IntByReference errorCode =new IntByReference();
    String sessionId = QTSR.INSTANCE.QISRSessionBegin(null, params,errorCode);

    运行效果:

    jna-yuyinshibie-04

    其他的函数处理方式大致相同,这里贴上一个c和java在jna中的类型对应表:

    Native Type Java Type
    char byte
    short short
    wchar_t char
    int int
    int boolean
    long NativeLong
    long long long
    float float
    double double
    char String
    void Pointer

    其中Unsigned类型和signed在java中对应是一样的。

    .h文件和常量处理

    在SDK的include目录有4个.h文件,定义了一些常量,比如上面一节中的0其实是msp_errors.h中MSP_SUCCESS。

    我以msp_errors.h为例,建立一个接口Msp_errors,继承StdCallLibrary。

    照着msp_errors.h中的定义在Msp_errors中进行定义。

    publicstaticfinalint MSP_SUCCESS =0;
    publicstaticfinalint ERROR_FAIL = -1;
    publicstaticfinalint ERROR_EXCEPTION= -2;
    publicstaticfinalint ERROR_GENERAL=10100;
    publicstaticfinalint ERROR_OUT_OF_MEMORY=10101;
    publicstaticfinalint ERROR_FILE_NOT_FOUND=10102;
    publicstaticfinalint ERROR_NOT_SUPPORT=10103;

    使用很简单的,比如MSP_SUCCESS 就是Msp_errors.MSP_SUCCESS。

    完整代码和文件

    这个只是语音识别部分的,语音合成的话我记得有人做过jni接口的。

    *QTSR.java

    package com.cnblogs.htynkn;
    
    import com.sun.jna.Library;
    import com.sun.jna.Native;
    import com.sun.jna.Pointer;
    import com.sun.jna.ptr.IntByReference;
    
    /**
    *@author 夜明的孤行灯
    *@date 2012-7-5
    */
    
    publicinterface QTSR extends Library {
    QTSR INSTANCE = (QTSR) Native.loadLibrary("msc", QTSR.class);
    
    /**
    * 初始化MSC的ISR部分
    *
    *@param configs
    * 初始化时传入的字符串,以指定合成用到的一些配置参数,各个参数以“参数名=参数值”的形式出现,大小写不敏感,不同的参数之间以“
    * ,”或“n”隔开,不设置任何值时可以传入NULL或空串:
    *@return 如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors
    */
    publicintQISRInit(String configs);
    
    /**
    * 开始一个ISR会话
    *
    *@param grammarList
    * uri-list格式的语法,可以是一个语法文件的URL或者一个引擎内置语法列表。可以同时指定多个语法,不同的语法之间以“,”
    * 隔开。进行语音听写时不需要语法,此参数设定为NULL或空串即可;进行语音识别时则需要语法,语法可以在此参数中指定,
    * 也可以随后调用QISRGrammarActivate指定识别所用的语法。
    *@param params
    * 本路ISR会话使用的参数,可设置的参数及其取值范围请参考《可设置参数列表_MSP20.xls》,各个参数以“参数名=参数值”
    * 的形式出现,不同的参数之间以“,”或者“n”隔开。
    *@param errorCode
    * 如果函数调用成功则其值为MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors。几个主要的返回值:
    * MSP_ERROR_NOT_INIT 未初始化 MSP_ERROR_INVALID_PARA 无效的参数
    * MSP_ERROR_NO_LICENSE 开始一路会话失败
    *@return MSC为本路会话建立的ID,用来唯一的标识本路会话,供以后调用其他函数时使用。函数调用失败则会返回NULL。
    */
    public StringQISRSessionBegin(String grammarList, String params,
    IntByReference errorCode);
    
    /**
    * 传入语法
    *
    *@param sessionID
    * 由QISRSessionBegin返回过来的会话ID。
    *@param grammar
    * 语法字符串
    *@param type
    * 语法类型,可以是uri-list、abnf、xml等
    *@param weight
    * 本次传入语法的权重,本参数在MSP 2.0中会被忽略。
    *@return 如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors
    */
    publicintQISRGrammarActivate(String sessionID, String grammar,
    String type,int weight);
    
    /**
    * 写入用来识别的语音
    *
    *@param sessionID
    * 由QISRSessionBegin返回过来的会话ID。
    *@param waveData
    * 音频数据缓冲区起始地址
    *@param waveLen
    * 音频数据长度,其大小不能超过设定的max_audio_size
    *@param audioStatus
    * 用来指明用户本次识别的音频是否发送完毕,可能值如下:
    * MSP_AUDIO_SAMPLE_FIRST = 1 第一块音频
    * MSP_AUDIO_SAMPLE_CONTINUE = 2 还有后继音频
    * MSP_AUDIO_SAMPLE_LAST = 4 最后一块音频
    *@param epStatus
    * 端点检测(End-point detected)器所处的状态,可能的值如下:
    * MSP _EP_LOOKING_FOR_SPEECH = 0 还没有检测到音频的前端点。
    * MSP _EP_IN_SPEECH = 1 已经检测到了音频前端点,正在进行正常的音频处理。
    * MSP _EP_AFTER_SPEECH = 3 检测到音频的后端点,后继的音频会被MSC忽略。
    * MSP _EP_TIMEOUT = 4 超时。
    * MSP _EP_ERROR= 5 出现错误。
    * MSP _EP_MAX_SPEECH = 6 音频过大。
    *@param recogStatus
    * 识别器所处的状态
    *@return
    */
    publicintQISRAudioWrite(String sessionID, Pointer waveData,int waveLen,
    int audioStatus, IntByReference epStatus, IntByReference recogStatus);
    
    /**
    * 获取识别结果
    *
    *@param sessionID 由QISRSessionBegin返回过来的会话ID。
    *@param rsltStatus 识别结果的状态,其取值范围和含义请参考QISRAudioWrite的参数recogStatus
    *@param waitTime 与服务器交互的间隔时间,可以控制和服务器的交互频度。单位为ms,建议取值为5000。
    *@param errorCode 如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors
    *@return 函数执行成功并且获取到识别结果时返回识别结果,函数执行成功没有获取到识别结果时返回NULL
    */
    public StringQISRGetResult(String sessionID, IntByReference rsltStatus,
    int waitTime, IntByReference errorCode);
    
    /**
    * 结束一路会话
    *
    *@param sessionID 由QISRSessionBegin返回过来的会话ID。
    *@param hints 结束本次会话的原因描述,用于记录日志,便于用户查阅或者跟踪某些问题。
    *@return
    */
    publicintQISRSessionEnd(String sessionID, String hints);
    
    /**
    * 获取与识别交互相关的参数
    *
    *@param sessionID 由QISRSessionBegin返回过来的会话ID。
    *@param paramName 要获取的参数名称;支持同时查询多个参数,查询多个参数时,参数名称按“,” 或“n”分隔开来。
    *@param paramValue 获取的参数值,以字符串形式返回;查询多个参数时,参数值之间以“;”分开,不支持的参数将返回空的值。
    *@param valueLen 参数值的长度。
    *@return
    */
    publicintQISRGetParam(String sessionID, String paramName,
    String paramValue, IntByReference valueLen);
    
    /**
    * 逆初始化MSC的ISR部分
    *
    *@return
    */
    publicintQISRFini();
    }

    *Msp_errors

    package com.cnblogs.htynkn;
    
    import com.sun.jna.win32.StdCallLibrary;
    
    /**
    *@author 夜明的孤行灯
    *@date 2012-7-5
    */
    
    publicinterface Msp_errors extends StdCallLibrary {
    publicstaticfinalint MSP_SUCCESS =0;
    publicstaticfinalint ERROR_FAIL = -1;
    publicstaticfinalint ERROR_EXCEPTION= -2;
    publicstaticfinalint ERROR_GENERAL=10100;/* 0x2774 */
    publicstaticfinalint ERROR_OUT_OF_MEMORY=10101;/* 0x2775 */
    publicstaticfinalint ERROR_FILE_NOT_FOUND=10102;/* 0x2776 */
    publicstaticfinalint ERROR_NOT_SUPPORT=10103;/* 0x2777 */
    publicstaticfinalint ERROR_NOT_IMPLEMENT=10104;/* 0x2778 */
    publicstaticfinalint ERROR_ACCESS=10105;/* 0x2779 */
    publicstaticfinalint ERROR_INVALID_PARA=10106;/* 0x277A */
    publicstaticfinalint ERROR_INVALID_PARA_VALUE=10107;/* 0x277B */
    publicstaticfinalint ERROR_INVALID_HANDLE=10108;/* 0x277C */
    publicstaticfinalint ERROR_INVALID_DATA=10109;/* 0x277D */
    publicstaticfinalint ERROR_NO_LICENSE=10110;/* 0x277E */
    publicstaticfinalint ERROR_NOT_INIT=10111;/* 0x277F */
    publicstaticfinalint ERROR_NULL_HANDLE=10112;/* 0x2780 */
    publicstaticfinalint ERROR_OVERFLOW=10113;/* 0x2781 */
    publicstaticfinalint ERROR_TIME_OUT=10114;/* 0x2782 */
    publicstaticfinalint ERROR_OPEN_FILE=10115;/* 0x2783 */
    publicstaticfinalint ERROR_NOT_FOUND=10116;/* 0x2784 */
    publicstaticfinalint ERROR_NO_ENOUGH_BUFFER=10117;/* 0x2785 */
    publicstaticfinalint ERROR_NO_DATA=10118;/* 0x2786 */
    publicstaticfinalint ERROR_NO_MORE_DATA=10119;/* 0x2787 */
    publicstaticfinalint ERROR_NO_RESPONSE_DATA=10120;/* 0x2788 */
    publicstaticfinalint ERROR_ALREADY_EXIST=10121;/* 0x2789 */
    publicstaticfinalint ERROR_LOAD_MODULE=10122;/* 0x278A */
    publicstaticfinalint ERROR_BUSY =10123;/* 0x278B */
    publicstaticfinalint ERROR_INVALID_CONFIG=10124;/* 0x278C */
    publicstaticfinalint ERROR_VERSION_CHECK=10125;/* 0x278D */
    publicstaticfinalint ERROR_CANCELED=10126;/* 0x278E */
    publicstaticfinalint ERROR_INVALID_MEDIA_TYPE=10127;/* 0x278F */
    publicstaticfinalint ERROR_CONFIG_INITIALIZE=10128;/* 0x2790 */
    publicstaticfinalint ERROR_CREATE_HANDLE=10129;/* 0x2791 */
    publicstaticfinalint ERROR_CODING_LIB_NOT_LOAD=10130;/* 0x2792 */
    
    /* Error codes of network 10200(0x27D8)*/
    publicstaticfinalint ERROR_NET_GENERAL=10200;/* 0x27D8 */
    publicstaticfinalint ERROR_NET_OPENSOCK=10201;/* 0x27D9 *//* Open socket */
    publicstaticfinalint ERROR_NET_CONNECTSOCK=10202;/* 0x27DA *//* Connect socket */
    publicstaticfinalint ERROR_NET_ACCEPTSOCK =10203;/* 0x27DB *//* Accept socket */
    publicstaticfinalint ERROR_NET_SENDSOCK=10204;/* 0x27DC *//* Send socket data */
    publicstaticfinalint ERROR_NET_RECVSOCK=10205;/* 0x27DD *//* Recv socket data */
    publicstaticfinalint ERROR_NET_INVALIDSOCK=10206;/* 0x27DE *//* Invalid socket handle */
    publicstaticfinalint ERROR_NET_BADADDRESS =10207;/* 0x27EF *//* Bad network address */
    publicstaticfinalint ERROR_NET_BINDSEQUENCE=10208;/* 0x27E0 *//* Bind after listen/connect */
    publicstaticfinalint ERROR_NET_NOTOPENSOCK=10209;/* 0x27E1 *//* Socket is not opened */
    publicstaticfinalint ERROR_NET_NOTBIND=10210;/* 0x27E2 *//* Socket is not bind to an address */
    publicstaticfinalint ERROR_NET_NOTLISTEN =10211;/* 0x27E3 *//* Socket is not listening */
    publicstaticfinalint ERROR_NET_CONNECTCLOSE=10212;/* 0x27E4 *//* The other side of connection is closed */
    publicstaticfinalint ERROR_NET_NOTDGRAMSOCK=10213;/* 0x27E5 *//* The socket is not datagram type */
    publicstaticfinalint ERROR_NET_DNS=10214;/* 0x27E6 *//* domain name is invalid or dns server does not function well */
    
    /* Error codes of mssp message 10300(0x283C) */
    publicstaticfinalint ERROR_MSG_GENERAL=10300;/* 0x283C */
    publicstaticfinalint ERROR_MSG_PARSE_ERROR=10301;/* 0x283D */
    publicstaticfinalint ERROR_MSG_BUILD_ERROR=10302;/* 0x283E */
    publicstaticfinalint ERROR_MSG_PARAM_ERROR=10303;/* 0x283F */
    publicstaticfinalint ERROR_MSG_CONTENT_EMPTY=10304;/* 0x2840 */
    publicstaticfinalint ERROR_MSG_INVALID_CONTENT_TYPE =10305;/* 0x2841 */
    publicstaticfinalint ERROR_MSG_INVALID_CONTENT_LENGTH =10306;/* 0x2842 */
    publicstaticfinalint ERROR_MSG_INVALID_CONTENT_ENCODE =10307;/* 0x2843 */
    publicstaticfinalint ERROR_MSG_INVALID_KEY=10308;/* 0x2844 */
    publicstaticfinalint ERROR_MSG_KEY_EMPTY=10309;/* 0x2845 */
    publicstaticfinalint ERROR_MSG_SESSION_ID_EMPTY=10310;/* 0x2846 */
    publicstaticfinalint ERROR_MSG_LOGIN_ID_EMPTY=10311;/* 0x2847 */
    publicstaticfinalint ERROR_MSG_SYNC_ID_EMPTY=10312;/* 0x2848 */
    publicstaticfinalint ERROR_MSG_APP_ID_EMPTY=10313;/* 0x2849 */
    publicstaticfinalint ERROR_MSG_EXTERN_ID_EMPTY=10314;/* 0x284A */
    publicstaticfinalint ERROR_MSG_INVALID_CMD=10315;/* 0x284B */
    publicstaticfinalint ERROR_MSG_INVALID_SUBJECT=10316;/* 0x284C */
    publicstaticfinalint ERROR_MSG_INVALID_VERSION=10317;/* 0x284D */
    publicstaticfinalint ERROR_MSG_NO_CMD=10318;/* 0x284E */
    publicstaticfinalint ERROR_MSG_NO_SUBJECT=10319;/* 0x284F */
    publicstaticfinalint ERROR_MSG_NO_VERSION=10320;/* 0x2850 */
    publicstaticfinalint ERROR_MSG_MSSP_EMPTY=10321;/* 0x2851 */
    publicstaticfinalint ERROR_MSG_NEW_RESPONSE=10322;/* 0x2852 */
    publicstaticfinalint ERROR_MSG_NEW_CONTENT=10323;/* 0x2853 */
    publicstaticfinalint ERROR_MSG_INVALID_SESSION_ID =10324;/* 0x2854 */
    
    /* Error codes of DataBase 10400(0x28A0)*/
    publicstaticfinalint ERROR_DB_GENERAL=10400;/* 0x28A0 */
    publicstaticfinalint ERROR_DB_EXCEPTION=10401;/* 0x28A1 */
    publicstaticfinalint ERROR_DB_NO_RESULT=10402;/* 0x28A2 */
    publicstaticfinalint ERROR_DB_INVALID_USER=10403;/* 0x28A3 */
    publicstaticfinalint ERROR_DB_INVALID_PWD=10404;/* 0x28A4 */
    publicstaticfinalint ERROR_DB_CONNECT=10405;/* 0x28A5 */
    publicstaticfinalint ERROR_DB_INVALID_SQL=10406;/* 0x28A6 */
    publicstaticfinalint ERROR_DB_INVALID_APPID=10407;/* 0x28A7 */
    
    /* Error codes of Resource 10500(0x2904)*/
    publicstaticfinalint ERROR_RES_GENERAL=10500;/* 0x2904 */
    publicstaticfinalint ERROR_RES_LOAD =10501;/* 0x2905 *//* Load resource */
    publicstaticfinalint ERROR_RES_FREE =10502;/* 0x2906 *//* Free resource */
    publicstaticfinalint ERROR_RES_MISSING =10503;/* 0x2907 *//* Resource File Missing */
    publicstaticfinalint ERROR_RES_INVALID_NAME =10504;/* 0x2908 *//* Invalid resource file name */
    publicstaticfinalint ERROR_RES_INVALID_ID =10505;/* 0x2909 *//* Invalid resource ID */
    publicstaticfinalint ERROR_RES_INVALID_IMG =10506;/* 0x290A *//* Invalid resource image pointer */
    publicstaticfinalint ERROR_RES_WRITE=10507;/* 0x290B *//* Write read-only resource */
    publicstaticfinalint ERROR_RES_LEAK =10508;/* 0x290C *//* Resource leak out */
    publicstaticfinalint ERROR_RES_HEAD =10509;/* 0x290D *//* Resource head currupt */
    publicstaticfinalint ERROR_RES_DATA =10510;/* 0x290E *//* Resource data currupt */
    publicstaticfinalint ERROR_RES_SKIP =10511;/* 0x290F *//* Resource file skipped */
    
    /* Error codes of TTS 10600(0x2968)*/
    publicstaticfinalint ERROR_TTS_GENERAL=10600;/* 0x2968 */
    publicstaticfinalint ERROR_TTS_TEXTEND =10601;/* 0x2969 *//* Meet text end */
    publicstaticfinalint ERROR_TTS_TEXT_EMPTY=10602;/* 0x296A *//* no synth text */
    
    /* Error codes of Recognizer 10700(0x29CC) */
    publicstaticfinalint ERROR_REC_GENERAL=10700;/* 0x29CC */
    publicstaticfinalint ERROR_REC_INACTIVE=10701;/* 0x29CD */
    publicstaticfinalint ERROR_REC_GRAMMAR_ERROR=10702;/* 0x29CE */
    publicstaticfinalint ERROR_REC_NO_ACTIVE_GRAMMARS =10703;/* 0x29CF */
    publicstaticfinalint ERROR_REC_DUPLICATE_GRAMMAR=10704;/* 0x29D0 */
    publicstaticfinalint ERROR_REC_INVALID_MEDIA_TYPE =10705;/* 0x29D1 */
    publicstaticfinalint ERROR_REC_INVALID_LANGUAGE=10706;/* 0x29D2 */
    publicstaticfinalint ERROR_REC_URI_NOT_FOUND=10707;/* 0x29D3 */
    publicstaticfinalint ERROR_REC_URI_TIMEOUT=10708;/* 0x29D4 */
    publicstaticfinalint ERROR_REC_URI_FETCH_ERROR=10709;/* 0x29D5 */
    
    /* Error codes of Speech Detector 10800(0x2A30) */
    publicstaticfinalint ERROR_EP_GENERAL=10800;/* 0x2A30 */
    publicstaticfinalint ERROR_EP_NO_SESSION_NAME=10801;/* 0x2A31 */
    publicstaticfinalint ERROR_EP_INACTIVE =10802;/* 0x2A32 */
    publicstaticfinalint ERROR_EP_INITIALIZED =10803;/* 0x2A33 */
    
    /* Error codes of TUV */
    publicstaticfinalint ERROR_TUV_GENERAL=10900;/* 0x2A94 */
    publicstaticfinalint ERROR_TUV_GETHIDPARAM =10901;/* 0x2A95 *//* Get Busin Param huanid*/
    publicstaticfinalint ERROR_TUV_TOKEN=10902;/* 0x2A96 *//* Get Token */
    publicstaticfinalint ERROR_TUV_CFGFILE=10903;/* 0x2A97 *//* Open cfg file */
    publicstaticfinalint ERROR_TUV_RECV_CONTENT =10904;/* 0x2A98 *//* received content is error */
    publicstaticfinalint ERROR_TUV_VERFAIL =10905;/* 0x2A99 *//* Verify failure */
    
    /* Error codes of IMTV */
    publicstaticfinalint ERROR_LOGIN_SUCCESS=11000;/* 0x2AF8 *//* 成功 */
    publicstaticfinalint ERROR_LOGIN_NO_LICENSE =11001;/* 0x2AF9 *//* 试用次数结束,用户需要付费 */
    publicstaticfinalint ERROR_LOGIN_SESSIONID_INVALID =11002;/* 0x2AFA *//* SessionId失效,需要重新登录通行证 */
    publicstaticfinalint ERROR_LOGIN_SESSIONID_ERROR=11003;/* 0x2AFB *//* SessionId为空,或者非法 */
    publicstaticfinalint ERROR_LOGIN_UNLOGIN =11004;/* 0x2AFC *//* 未登录通行证 */
    publicstaticfinalint ERROR_LOGIN_INVALID_USER =11005;/* 0x2AFD *//* 用户ID无效 */
    publicstaticfinalint ERROR_LOGIN_INVALID_PWD =11006;/* 0x2AFE *//* 用户密码无效 */
    publicstaticfinalint ERROR_LOGIN_SYSTEM_ERROR=11099;/* 0x2B5B *//* 系统错误 */
    
    /* Error codes of HCR */
    publicstaticfinalint ERROR_HCR_GENERAL=11100;
    publicstaticfinalint ERROR_HCR_RESOURCE_NOT_EXIST =11101;
    publicstaticfinalint ERROR_HCR_CREATE=11102;
    publicstaticfinalint ERROR_HCR_DESTROY=11103;
    publicstaticfinalint ERROR_HCR_START=11104;
    publicstaticfinalint ERROR_HCR_APPEND_STROKES=11105;
    publicstaticfinalint ERROR_HCR_GET_RESULT=11106;
    publicstaticfinalint ERROR_HCR_SET_PREDICT_DATA=11107;
    publicstaticfinalint ERROR_HCR_GET_PREDICT_RESULT =11108;
    
    /* Error codes of http 12000(0x2EE0) */
    publicstaticfinalint ERROR_HTTP_BASE=12000;/* 0x2EE0 */
    
    /*Error codes of ISV */
    publicstaticfinalint ERROR_ISV_NO_USER =13000;/* 32C8 *//* the user doesn't exist */
    
    /* Error codes of Lua scripts */
    publicstaticfinalint ERROR_LUA_BASE=14000;/* 0x36B0 */
    publicstaticfinalint ERROR_LUA_YIELD=14001;/* 0x36B1 */
    publicstaticfinalint ERROR_LUA_ERRRUN=14002;/* 0x36B2 */
    publicstaticfinalint ERROR_LUA_ERRSYNTAX=14003;/* 0x36B3 */
    publicstaticfinalint ERROR_LUA_ERRMEM=14004;/* 0x36B4 */
    publicstaticfinalint ERROR_LUA_ERRERR=14005;/* 0x36B5 */
    }

    嫌复制粘贴麻烦的可以点击下面的链接下载:

    Msp_errors.java: http://www.t00y.com/file/8170772
    QTSR.java: http://www.t00y.com/file/8170775

  • 在win7上部署umbraco

    在win7上部署umbraco

    什么是umbraco

    Umbraco是一个开放源码的CMS内容管理系统,基于asp.net建立,使用mssql进行存储数据。 使用Umbraco ,设计师能创造出有效的XHTML标记模板和开发人员可以创建任何基于.Net的模块。主要特点包括:

    • 漂亮,友好的用户界面
    • 综合所见即所得编辑器
    • 支持编辑在Microsoft Word
    • 全部源代码可用(开放源代码)
    • 超级简单的模板引擎
    • 完全支持Web标准

    最近需要把一个asp的软件下载站点转移到asp.net,数据库最好用MSSQL。在网上Google一番以后决定试试umbraco,看着一大票的英文文档是在有些难受,还是先看看umbraco是什么样子的再研究文档。我的电脑是Win7的,装了MSSQL 2005 DEV和VS2010,没有IIS7。

    获取umbraco

    umbraco的官网是:http://www.umbraco.org/

    下载地址:http://www.umbraco.org/download

    还有一个中文的爱好者网站:http://www.umbracochina.com/

    这个中文网站提供了汉化包,针对4.7和4.X版本(是这么写着的),但是我不推荐用这个。因为文档毕竟没有汉化,汉化的界面虽然看着舒服,但是文档有些东西就对不上了。当然个人观点哈。

    umbraco-win7-1

    下载界面最上面的是针对Microsoft Web Platform Installer or WebMatrix的,没用过…

    点下面那个下到4.7.2的编译好的版本,直接解压到D盘去,在IIS中新建一个站点,然后访问…

    错误和解决

    访问直接报服务器错误:HTTP 错误 500.19 – Internal Server Error,无法访问请求的页面,因为该页的相关配置数据无效。

    umbraco-win7-2

    看情况是缺少配置,我打开Web.config确实没有这个节点的配置。我比较好奇为什么这个有名的一个开源项目的配置有错误…难道是我无意中跳了步骤?

    不管了,参考一下标准配置将配置文件补全,在configSections节点中添加:

    <sectiongroupname="system.web.extensions"type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
    <sectiongroupname="scripting"type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
    <sectionname="scriptResourceHandler"type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"requirepermission="false"allowdefinition="MachineToApplication">
    <sectiongroupname="webServices"type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
    <sectionname="jsonSerialization"type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"requirepermission="false"allowdefinition="Everywhere">
    <sectionname="profileService"type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"requirepermission="false"allowdefinition="MachineToApplication">
    <sectionname="authenticationService"type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"requirepermission="false"allowdefinition="MachineToApplication">
    <sectionname="roleService"type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"requirepermission="false"allowdefinition="MachineToApplication">
    </section></section></section></section></sectiongroup>
    </section></sectiongroup>
    </sectiongroup>

    插入位置应该没有影响吧。

    umbraco-win7-3

    然后访问..继续报错,不过这次是应用程序错误了:无法识别的属性“targetFramework”。请注意属性名称区分大小写。

    umbraco-win7-5

    这个问题我先没有在意准备下个Net4.0安装,然后我发现我已经安装了(应该是Vs2010一起的)。然后在网上问了问,才知道是顺序问题。

    我的安装顺序是:VS2010+MSSQL+IIS7。

    也就是Net4安装的时候没有注册IIS。切换到命令行执行“C:WindowsMicrosoft.NETFrameworkv4.0.30319aspnet_regiis.exe /i ”注册。

    umbraco-win7-6

    切换到IIS配置中去,将网站的应用程序池改成4.0。

    umbraco-win7-7

    然后刷新,完成~

    安装

    网页自动跳转到install中去了。

    umbraco-win7-8

    原来umbraco还支持mysql。

    第二步同意umbraco的协议。

    umbraco-win7-9

    MIT许可证之名源自麻省理工学院(Massachusetts Institute of Technology, MIT),被授权人权利大限制少。

    不知为何页面下面有些乱码…

    第三步配置数据库,没有的话可以用用SQL CE 4。

    填写完成后会初始化数据库。

    umbraco-win7-10

    第四步配置管理员,最下面的复选框是订阅。

    umbraco-win7-11

    第五步选择新手包

    umbraco-win7-12

    新手包其实就是初始化一些模型和页面,方便学习。官方写的第一个最适合新手,不过我比较推荐Blog。

    umbraco-win7-13

    这个效果让我觉得很新鲜哈。

    皮肤随便选一个就行了。

    umbraco-win7-14

    完成了…奇怪的地方掺杂了一些乱码…

    umbraco-win7-15

     前台效果:

    umbraco-win7-16

    这里有学习的引导

    后台效果:

    umbraco-win7-17

    写在最后

    umbraco比我预想的要好很多,最近准备好好研究研究。

    注:好吧…官网的链接没有更新,我下载的是4.7.2版本的…最新是5.2了

    5.2使用的mvc,如果出现未能加载文件或程序集“System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”或它的某一个依赖项。系统找不到指定的文件。尝试安装mvc3。

     

  • Ormlite在一般java环境中操作Sqlite

    Ormlite在一般java环境中操作Sqlite

    简介

    最开始接触ormlite是在android的开发中,ormlite的简单便利让我印象深刻。

    这几天在研究顾客购物行为,需要使用到数据库,但是对于数据库的速度什么的要求不大,我首先想到的是Ormlite+Sqlite。

    实体类

    ormlite的官网http://ormlite.com/,最新版本4.41

    因为是在一般java环境中使用,所以不需要那个android包。

    ormlite-sqlite

    引入包以后建立modal,例如:Commodity.java。因为使用的sqlite,主键自增长,设置为

    @DatabaseField(generatedId =true)

    完整的代码如下:

    package com.cnblogs.htynkn.DataSpider.Modal;
    
    import com.j256.ormlite.field.DatabaseField;
    import com.j256.ormlite.table.DatabaseTable;
    
    /**
    *@author 夜明的孤行灯
    *@date 2012-6-29
    */
    
    @DatabaseTable(tableName ="Commodity")
    publicclass Commodity {
    @DatabaseField(generatedId =true)
    privateint id;
    @DatabaseField(columnName ="Name")
    private String name;
    @DatabaseField(columnName ="JdKey")
    private String jdKey;
    @DatabaseField(columnName ="TbKey")
    private String tbKey;
    
    publicCommodity() {
    
    }
    
    publicintgetId() {
    return id;
    }
    
    publicvoidsetId(int id) {
    this.id = id;
    }
    
    public StringgetName() {
    return name;
    }
    
    publicvoidsetName(String name) {
    this.name = name;
    }
    
    public StringgetJdKey() {
    return jdKey;
    }
    
    publicvoidsetJdKey(String jdKey) {
    this.jdKey = jdKey;
    }
    
    public StringgetTbKey() {
    return tbKey;
    }
    
    publicvoidsetTbKey(String tbKey) {
    this.tbKey = tbKey;
    }
    }

    获取Dao

    ormlite在android中的使用比较方便,有兴趣的朋友可以参考http://www.cnblogs.com/htynkn/archive/2011/10/30/android_ormlite_1.html

    在上面的那篇文章中我们的DataHelper继承了OrmLiteSqliteOpenHelper。这是类是ormlite-android特有的。在一般的java环境中使用还不能这么简单。

    Ormlite的官网有提到从jdbc入手,使用DaoManager创建Dao。比如:

    String connectionString ="jdbc:sqlite:data.db";

    意思是使用当前目录的data.db文件。ormlite没有包含sqlite的jdbc包,我们需要自己去下载一个。

    这个地方一定要注意,sqlite的jdbc包有很多,我们必须要支持主键自增长那种。比如Xerial driver,我最开始使用的是Zentus driver,怎么弄都弄不起。

    使用

    DaoManager.createDao(GetConnectionSource(),Commodity.class);

    获取Dao<Commodity, Integer>。如果需要创建表,可以使用TableUtils。

    完整代码如下:

    package com.cnblogs.htynkn.DataSpider.Data;
    
    import java.sql.SQLException;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import com.cnblogs.htynkn.DataSpider.Modal.Commodity;
    import com.cnblogs.htynkn.DataSpider.Modal.TransactionRecord;
    import com.j256.ormlite.dao.Dao;
    import com.j256.ormlite.dao.DaoManager;
    import com.j256.ormlite.jdbc.JdbcConnectionSource;
    import com.j256.ormlite.support.ConnectionSource;
    import com.j256.ormlite.table.TableUtils;
    
    /**
    *@author 夜明的孤行灯
    *@date 2012-6-29
    */
    
    publicclass SqliteOpenHelper {
    privatestatic Log log = LogFactory.getLog(SqliteOpenHelper.class);
    privatestatic Dao
    privatestatic Dao commodityDao;
    
    publicstatic DaoGetCommodityDao()throws SQLException {
    if (commodityDao ==null) {
    commodityDao = DaoManager.createDao(GetConnectionSource(),
    Commodity.class);
    }
    return commodityDao;
    }
    
    publicstaticvoidinit() {
    try {
    TableUtils.createTable(GetConnectionSource(), Commodity.class);
    }catch (Exception exception) {
    log.warn("创建Commodity表失败 : " + exception.getMessage());
    }
    }
    
    publicstatic ConnectionSourceGetConnectionSource()throws SQLException {
    String connectionString ="jdbc:sqlite:data.db";
    returnnew JdbcConnectionSource(connectionString);
    }
    }

     

    高级查询

    ormlite的Dao支持简单的添加、删除、修改还有按照Id查询,当然也可以使用原生的SQL。如果需要条件查询就需要使用QueryBuilder了。

    QueryBuilder qb = dao.queryBuilder();

    举个例子,我们需要查询一个时间段的数据

    qb.where().between("TransactionTime", start, end);
    return qb.query();

    这里会返回一个List,然后在继续处理就行了。

    如果确实需要使用原生的SQL语句就可以用

    dao.queryRaw(query, arguments)
  • 基于LingPipe的文本倾向性分析–LingPipe学习笔记

    基于LingPipe的文本倾向性分析–LingPipe学习笔记

    文本倾向性分析

    文本倾向性分析(情感分析 )是将用户的观点分为“正面”和“负面”,有时候会多一个“中性”。文本倾向性分析一个比较直观的应用就是追踪用户对于一个事物的观点和偏好,比如分析豆瓣上一个电影的评论进行分析。正因为如此情感分析又被称为观点挖掘。

    LingPipe

    lingpipe 是alias公司开发的一款自然语言处理软件包,包括主题分类、句题检测、字符语言建模等十余个模块。而且文档完整,甚至每一个算法都有论文参考。更难能可贵的是它支持中文。

    官方地址:http://alias-i.com/lingpipe/

    下载地址:http://alias-i.com/lingpipe/web/download.html

    LingPipe分为两个大块,一块是LingPipe核心文件,另外一块是LingPipe的模型类。需要支持中文的话需要下载Chinese Word Segmentation模块。

    准备语料库

    语料库在语言学上意指大量的文本,通常经过整理,具有既定格式与标记。

    一般而言做情感分析有个很重要的步骤就是采集观点并进行整理,但由于应用场景不同,处理方法也不同。为了方便起见,这里使用已经处理好的语料库。Movie Review Data的polarity dataset v2.0,包含1000个正面的观点和1000个负面观点。当然这个是英文的哈。

    基本极性分析

    基本极性是指事物从样本来看所处的整体倾向,比如:一本书,用户对其的情感倾向是正面的,这样的断言就是一个基本极性断言。

    基本极性的分析直接使用LingPipi的DynamicLMClassifier即可。

    大致上来讲分为两步,第一步训练,第二步进行分析。

    新建一个类名为PolarityBasic。

    publicPolarityBasic(String basePath) {
    pDir =new File(basePath,"txt_sentoken");//获取语料集
    categories = pDir.list();//获取类别
    int nGram =4;
    classifer = DynamicLMClassifier.createNGramProcess(categories, nGram);//新建动态分类器
    }

    我们先来看看如何训练。

    publicvoidtrain()throws IOException {
    for (int i =0; i < categories.length; ++i) {
    String category = categories[i];
    Classification classification =new Classification(category);//新建类别
    File dir =new File(pDir, categories[i]);
    File[] trainFiles = dir.listFiles();
    for (int j =0; j < trainFiles.length; ++j) {
    File trainFile = trainFiles[j];
    if (isTrainingFile(trainFile)) {//判断一下是为了让一部分数据作为训练集、一部分作为测试集
    String review = Files.readFromFile(trainFile,"ISO-8859-1");
    Classified classified =new Classified(
    review, classification);//指定内容和类别
    classifer.handle(classified);//训练
    }
    }
    }
    }

    这里说明一下isTrainingFile方法。我们需要一份测试集和一个训练集,但是我们只有一个语料库,只有人为分割。我原本是每次随机数一下来干的,但是有点影响速度,这里直接用文件名作为判断依据了。

    boolean isTrainingFile(File file) {
    return file.getName().charAt(2) !='1';//如果第2位为1就是测试集
    }

    训练完成后使用classifer就可以进行极性分析了。

    publicvoidevaluate()throws IOException {
    int numTests =0;
    int numCorrect =0;
    for (int i =0; i < categories.length; ++i) {
    String category = categories[i];
    File file =new File(pDir, categories[i]);
    File[] testFiles = file.listFiles();
    for (int j =0; j < testFiles.length; ++j) {
    File testFile = testFiles[j];
    if (!isTrainingFile(testFile)) {
    String review = Files.readFromFile(testFile,"ISO-8859-1");
    ++numTests;
    Classification classification = classifer.classify(review);
    String resultCategory = classification.bestCategory();
    if (resultCategory.equals(category))
    ++numCorrect;
    }
    }
    }
    System.out.println("测试总数:" + numTests);
    System.out.println("正确数:" + numCorrect);
    System.out.println("正确率" + ((double) numCorrect)
    / (double) numTests);
    }

    效果:

    lingpipe1

    将isTrainingFile修改一下

    boolean isTrainingFile(File file) {
    return file.getName().charAt(2) !='2';//如果第2位为2就是测试集
    }

    lingpipi2

    就正确率而言怎么划分训练集和测试集影响不大。

    还可以这样划分

    boolean isTrainingFile(File file) {
    return (file.getName().charAt(2) !='2')&&(file.getName().charAt(2) !='1');
    }

    扩展

    基本极性分析只是文本倾向性分析一个很简单的部分,如果需要深入的话,LingPipe还可以实现主观性分析、层次极性分析等。

    如果需要支持中文的话,请下载words-zh-as.CompiledSpellChecker。

    最后附上三篇参考文献:

  • RIpple-DOwn Rule算法和weka中Rider使用–数据挖掘学习和weka使用(五)

    RIpple-DOwn Rule算法和weka中Rider使用–数据挖掘学习和weka使用(五)

    RIpple-DOwn Rule算法简介

    RIpple-DOwn Rule算法(链波下降规则)是一种专家系统方法论,它是澳大利亚新南威尔士大学的Compton教授于1989年提出。它是一种用于知识表示和获取的方法。从某种意义上看RDR算法是CBR方法的一种扩展或者变形,RDR将规则引入CBR中,用规则来索引案例,以错误驱动机制来获取知识。

    RIpple-DOwn Rule算法是比较简单,有时候得出的结果不能让人满意,但是它是我最喜欢的一种算法,它通过否定规则来表示结果,非常适合人类理解。

    RIpple-DOwn Rule算法流程

    RIpple-DOwn Rule算法使用了二元决策树,区别于标准决策树,RDR用复合条款是来确定分支,同时这些条款不需要详尽涵盖所有情况,即可以有分类错误的情况,然后用错误的数据作为新整体再处理,以获得内部分支。

    为了方便说明,我们先看一个RDR的输出

    weka5_1

    这是一个医学诊断系统的涟波规则。

    我们还是以weather.arff的数据为例。

    weka5_2

    看一下我们的分类要求,要分成no和yes两类。

    no 的权重是5,yes的权重是9。

    由错误驱动生成第一条规则

    play = no

    很明显这条规则没有正确分类

    weka5_3

    总共14个样本,有9个被分类错了。

    再来生成内规则。

    生成过程就省略了…请参考本文最后的参考文献。第二条规则是

    Except (humidity <= 82.5) => play = yes

    序号为6的数据被错误分类为play了.最终的规则是

    play = no

               Except (humidity <= 82.5) => play = yes

    最终的规则分类正确10个,错误4个,正确率71.4286 %。

    比较图如下:

    weka5_4

    左边是分类结果,右边是原始结果。

    使用Weka实现RDR算法

    在weka中RDR算法对应的类是Rider,我使用的是3.6,3.7版本没有找个类了…

    核心代码:

    Ridor ridor =new Ridor();
    ridor.buildClassifier(instances);

    使用:

    ridor.classifyInstance(instance)

    还是使用weather数据,完整代码如下:

    import weka.classifiers.Evaluation;
    import weka.classifiers.rules.Ridor;
    import weka.core.Instances;
    import weka.core.converters.ConverterUtils.DataSource;
    
    publicclass MainStarter {
    
    publicstaticvoidmain(String[] args) throws Exception {
    System.out.println("start");
    
    Instances instances = DataSource.read("data/weather.arff");
    instances.setClassIndex(instances.numAttributes() -1);
    System.out.println(instances.toSummaryString());
    
    Ridor ridor =new Ridor();
    ridor.buildClassifier(instances);
    System.out.println(ridor.toString());
    
    Evaluation eval =new Evaluation(instances);
    eval.evaluateModel(ridor, instances);
    System.out.println(eval.toSummaryString("nResultsn======n",false));
    
    Instancesin =new Instances(instances);
    
    in.setClassIndex(0);
    in.deleteAttributeAt(in.numAttributes() -1);
    for (int i =0; i <in.numInstances() -1; i++) {
    System.out.println(in.instance(i).toString() +":"
    + ridor.classifyInstance(in.instance(i))+"--"+instances.instance(i).classValue());
    }
    System.out.println("end");
    }
    }

    结果:

    weka5_5

    相关参考

    没有细致的介绍RIpple-DOwn Rule算法主要是因为这个算法虽然简单,但实现方法比较多,又涉及到拓扑和集合运算,有兴趣的可以参考一下:

    Induction of Ripple-Down Rules Applied to Modeling Large Databases

  • OneR算法和weka中OneR使用–数据挖掘学习和weka使用(四)

    OneR算法和weka中OneR使用–数据挖掘学习和weka使用(四)

    OneR算法简介

    OneR又称1-R,是1993出现的一种极为简单的分类算法模型,它可以产生一个单层的决策树。

    OneR算法是一个简单、廉价的方法,但是常常能够获得一个非常好的结果,用于描述数据中的结构。

    OneR算法的使用非常广泛,可以简单的得到一个对数据的概括性了解,有时候甚至可以直接获得结果。

    OneR算法实现

    OneR的思路很简单,建立一个只针对于单个属性进行测试的规则,并进行不同的分支。每个分支对应的不同属性值。

    分支的类就是原始数据(训练数据)在这个分支上出现最多的类。

     

    每一个属性都会产生一个不同的规则集,每条规则对应这个属性的每个值。对每个属性值的规则集的误差率进行评估,选择效果最好的一个即可。

    伪代码表述:

    对于每个属性

      对于这个属性的每个属性值,建立如下规则

        计算每个类别出现的频率

        找出出现最频繁的类别

        建立规则,将这个类别赋予这个属性值

      计算规则的误差率

    选择误差率最小的规则

     

    一个简单的例子,数据使用weka自带的weather数据集。

    weka4_1

    针对每个属性,一共有5个,其中最后一个是我们希望输出的结果,所以只有4个属性值。即outlook、temperature、humidity、windy。

    我们先计算outlook属性,它有3个属性值,sunny、rainy、overcast。

    weka4_2

    针对属性值sunny而言,一共有5条数据。

    weka4_3

    其中对应play为no的有3条、对应play为yes的有2条,为no的最频繁,所以给sunny赋值为no。

    同理对于rainy而言,有5条记录。

    weka4_4

    其中对应play为yes的有3条、对应play为no的有2条,为yes的最频繁,所以给rainy赋值为yes。

    同理计算overcast属性值,赋值为yes。

     

    然后计算误差率

    sunny—>no 中有3个分类正确,2个分类错误,误差0.4

    rainy—>yes 误差为0.4

    overcast—>yes 误差为0

    outlook总误差4/14

     

    然后依次计算temperature、humidity、windy属性,并计算误差和总误差。然后选择误差最小的(相同则随意取或者取稳定度高的)。

    最后结果为

    sunny—>no
    
    rainy—>yes
    
    overcast—>yes

     

    使用Weka实现OneR算法

    weka自身已经实现了OneR算法,位于weka.classifiers.rules包中。

    OneR可以传入一个参数,如果是一个连续值,而且你希望离散化它们的话可以指定一个桶大小。

    Instances instances =DataSource.read("data/weather.arff");
    instances.setClassIndex(instances.numAttributes() -1);
    System.out.println(instances.toSummaryString());
    
    OneR oneR =newOneR();
    oneR.setDebug(false);
    oneR.setMinBucketSize(6);
    oneR.buildClassifier(instances);
    System.out.println(oneR.toString());

    效果:

    weka4_5

    如果将桶大小设为1,结果将会有很大不同。

    weka4_6

    很明显前一个结果的用处要大很多。

    相关参考

    关于OneR的相关,最好的参考自然是1993年R.C. Holte所著相关文章Very simple classification rules perform well on most commonly used datasets,页码是63-91页。

    附上下载地址:http://www.ctdisk.com/file/6000694

  • android游戏开发框架libgdx的使用(二十)—资源预加载与AssetManager的使用

    本文使用的libgdx是0.92版本,和现在的最新版可能有一些不一样的地方。全文内容仅供参考。

    好久没有写libgdx相关的东西了,主要是我不知道改写些什么了。

    最近收到了很多邮件,大多是关于资源加载的,特别是异步资源加载,还有什么Loading窗口的实现什么的,这篇博文就做个大致的回答吧。

    什么时候需要资源预加载

    资源预加载的目的很明确,提升用户体验。当然就开发者而言,比较好的预加载实现方式还可以方便管理。

    如果游戏很简单简单,资源很少很少,那么弄资源预加载就是费事,但是以下几种情况的话还是推荐使用:

    1.资源数量大

    音乐、图片、视频什么的,如果你的游戏这些东西太多,推荐使用

    2.部分资源反复使用

    有些资源会反复使用到,比如一些背景音乐,一些小图标

    Libgdx中的AssetManager

    AssetManager是libgdx提供的资源加载方案,demo中有个例子,详细的可以细致参考。

     

    AssetManager使用很简单,先实例化一个。

    AssetManager assetManager =new AssetManager();

    加载资源时需要制定资源位置和资源类型,目前支持Pixmaps、Textures、BitmapFonts、TextureAtlases、TiledAtlases、TileMapRenderers、Music、Sound这些类型的资源。

    使用方法:

    assetManager.load("data/img/bg.png", Texture.class);assetManager.load("data/font/chinese.fnt", BitmapFont.class);assetManager.load("data/music/op_head.ogg", Music.class);assetManager.load("data/pack/task1.pack", TextureAtlases.class);

    加载的时候还支持自定义参数,比如加载Texture时

    TextureParametertextureParameter = new TextureParameter();textureParameter.minFilter = TextureFilter.Linear;textureParameter.genMipMaps =true;manager.load("data/img/bg.png", Texture.class, textureParameter);

    大多数情况还是不用考虑自定义参数的。

     

    执行了Load方法其实只是将预加载的资源载入了队列,实质上并没有加载什么,使用Update方法才会加载资源。

    该方法有个返回值,当其为True时即加载完成,为False就表示还在加载。

    如果需要一个比较准确的返回,比如当前加载到百分之多少了以方便绘制进度条,可以使用getProgress方法,该方法返回一个0到1之间的数字。

    获取资源时候使用assetManager.get(位置,类型)即可,比如

    assetManager.get("data/img/bg.png", Texture.class);assetManager.get("data/font/chinese.fnt", BitmapFont.class);

    如果有需要也可以先检查一下

    assetManager.isLoaded("data/img/bg.png")

    使用时的一些注意事项

    如果要取消预加载的话,调用finishLoading方法。

    如果要销毁使用完的资源的话,调用unload方法。

    还有一个比较重大的问题就是游戏被打断以后,部分资源需要重新加载,不然的话会出现无数报错⊙﹏⊙b汗

  • 数据预处理和weka.filters的使用–数据挖掘学习和weka使用(三)

    数据预处理和weka.filters的使用–数据挖掘学习和weka使用(三)

    上一篇介绍了arff格式,这是weka专有格式,一般情况需要我们从其他数据源抽取或者获得。weka支持从cvs转化,也可以从数据库中抽取,界面如下图

    weka3_1

    weka安装目录有一个data目录,里面有一些测试数据,可以用于测试和学习。

    导入了数据仅仅是一个开始,我们还需要对数据进行预处理。

    数据预处理(data preprocessing)

    数据预处理(data preprocessing)是指在主要的处理以前对数据进行的一些处理。

    现实世界中数据大体上都是不完整,不一致的脏数据,无法直接进行数据挖掘,或挖掘结果差强人意。

    为了提高数据挖掘的质量产生了数据预处理技术。

    数据预处理有多种方法:数据清理,数据集成,数据变换,数据归约等。这些数据处理技术在数据挖掘之前使用,大大提高了数据挖掘模式的质量,降低实际挖掘所需要的时间。

    数据清理是使用比较频繁的,主要有:

    (1)空缺值处理

    目前最常用的方法是使用最可能的值填充空缺值,比如可以用回归、贝叶斯形式化方法工具或判定树归纳等确定空缺值.这类方法依靠现有的数据信息来推测空缺值,使空缺值有更大的机会保持与其他属性之间的联系。

    还可以用一个全局常量替换空缺值、使用属性的平均值填充空缺值或将所有元组按某些属性分类,然后用同一类中属性的平均值填充空缺值.如果空缺值很多,这些方法可能误导挖掘结果。

    (2)噪声数据处理

    噪声是一个测量变量中的随机错误或偏差,包括错误的值或偏离期望的孤立点值。常用分箱、回归、计算机检查和人工检查结合、聚类等方法进行噪音处理。

     

    数据变化主要使用平滑聚集,数据概化,规范化等手段使数据换为较利于数据挖掘的格式。

     

    数据归约主要是为了压缩数据量,源数据可以用来得到数据集的归约表示,它接近于保持原数据的完整性,但数据量比原数据小得多.与非归约数据相比,在归约的数据上进行挖掘,所需的时间和内存资源更少,挖掘将更有效,并产生相同或几乎相同的分析结果。常用维归约、数据压缩、数值归约等方法实现。

    Weka.Filters

    weka.filters中包含了一些数据预处理的简单实现(其实已经够用了),主要分成两大类,监督过滤(UnsupervisedFilter)和非监督过滤(UnsupervisedFilter)。

    如果是使用GUI的话,点击Filter的Choose就可以选择

    weka3_2

    选择完成后点击选择的Filter本身就可以修改相关参数。

    weka3_3

    完成参数修正后点击Apply就Ok了。

    我平时使用的比较多的还是非监督过滤,下面介绍一些比较常见。

    先介绍weka.filters.unsupervised.attribute包下的,这是非监督方法对属性进行预处理。

    1.Add

    为数据库添加一个新的属性,新的属性将会包含所有缺失值。可选参数:

    attributeIndex:属性位置,从1开始算,last是最后一个,first是第一个

    attributeName:属性名称

    attributeType:属性类型,一般是4选1

    dateFormat:数据格式,参考ISO-8601

    nominalLabels:名义标签,多个值用逗号隔开

    2.AddExpression

    新增一个属性,该属性由现有属性通过设定的表达式计算得出。支持+, -, *, /, ^, log, abs, cos, exp, sqrt, floor, ceil, rint, tan, sin。现有属性由a+索引值构成。

    3.AddID

    字面意思,添加一个ID

    4.AddNoise

    只对名义属性有效,依照一定比例修改值。

    5.Center

    将数值化属性的平均化为0。

    6.ChangeDateFormat

    修改数据格式

    7.Copy

    复制制定属性并命名为Copy Of XX

    8.Discretize

    简单划分的离散化处理。参数:

    attributeIndices:属性范围,如1-5,first-last

    bins:桶的数量

    9.FirstOrder

    第n个值用n+1项值和n项值的差替换

    10.MathExpression

    功能和AddExpression类似,不过支持的运算更多,特别是MAX和MIN的支持特别有用。所有支持运算符如下:+, -, *, /, pow, log,abs, cos, exp, sqrt, tan, sin, ceil, floor, rint, (, ),A,MEAN, MAX, MIN, SD, COUNT, SUM, SUMSQUARED, ifelse

    11.Reorder

    重新排列属性,输入2-last,1可以让第一项排到最后,如果输入1,3,5的话…其他项就没有了

    12.Standardize

    这个和Center功能大致相同,多了一个标准化单位变异数

    13.StringToNominal

    将String型转化为Nominal型

    14.SwapValues

    交换值

    然后是weka.filters.unsupervised.instance包下的

    1.NonSparseToSparse

    将所有输入转为稀疏格式

    2.Normalize

    规范化整个实例集

    3.RemoveFolds

    交叉验证,不支持分层,如果需要的话使用监督学习中的方法

    4.RemoveRange

    移除制定范围的实例,化为NaN

    5.Resample

    随机抽样,从现有样本产生新的小样本

    6.SubsetByExpression

    根据规则进行过滤,支持逻辑运算,向上取值,取绝对值等等

    weka.filters.supervised包中的内容比较少,而且涉及到一些流程原理,这里就不介绍了,后面的文章会慢慢介绍到

    调用Weka实现数据预处理

    weka的使用并不仅仅极限于它自带的GUI或者命令行,我们可以使用weka的java api,在weka的基础架构和已经实现的算法基础上进行开发。

    新建一个java项目,添加对weka.jar的引用。这个包一般在安装目录下,我的3.6版本的大小为6316kb。

    Instances是最主要的数据集容器,读入arff文件初始化之,如下:

    Instances instances=DataSource.read("data/cpu.arff");
    System.out.println(instances.toSummaryString());

    效果:

    weka3_4

    使用Filter的一般流程是:实例化过滤器,传入过滤器参数,通过Filter.useFilter使用过滤器

    举个例子,我想为这个cpu数据库加入一个ID,使用AddID过滤器。

    先实例化AddID

    AddID filter =new AddID();

    该过滤器需要2个参数,一个是位置,一个是名称。建立一个长为4的字符串数组,填充参数

    String[] options =new String[4];
    options[0] ="-C";
    options[1] ="first";
    options[2] ="-N";
    options[3] ="ID";
    filter.setOptions(options);
    filter.setInputFormat(instances);

    使用过滤器,然后输出

    Instances newInstances =Filter.useFilter(instances,filter);
    System.out.println(newInstances.toSummaryString());

    完整代码:

    Instances instances = DataSource.read("data/cpu.arff");
    System.out.println(instances.toSummaryString());
    AddID filter =new AddID();
    String[] options =new String[4];
    options[0]="-C";options[1]="first";options[2]="-N";options[3]="ID";filter.setOptions(options);filter.setInputFormat(instances);
    Instances newInstances = Filter.useFilter(instances, filter);
    System.out.println(newInstances.toSummaryString());

    效果:

    再演示一个离散化过滤的使用和新数据的保存

    Discretize discretize =new Discretize();
    options=new String[6];
    options[0]="-B";
    options[1]="8";
    options[2]="-M";
    options[3]="-1.0";
    options[4]="-R";
    options[5]="2-last";
    discretize.setOptions(options);
    discretize.setInputFormat(newInstances);
    Instances newInstances2 = Filter.useFilter(newInstances, discretize);
    System.err.println(newInstances2.toSummaryString());DataSink.write("data/newcpu.arff",newInstances2);

    其实可以很明显的看出,java调用weka api并不困难,关键还是对于数据挖掘、weka本身的了解和熟悉,对于使用哪种方法,需要什么参数要有一定概念。

    weka的扩展,实现自己的过滤器

    我使用的weka版本是3.6.6,要是版本不同的话可能有些细节有差异。

    一切的开始是Filter类,然后是SimpleFilter,一般情况下我们继承SimpleStreamFilter、SimpleBatchFilter。

    这两个的本质差别是一个是全部读入,一个是数据流式处理,但是代码可以完全一样,主要是效率和使用空间上的区别。

    举个例子,我希望将所有属性都进行向下取整,继承SimpleStreamFilter,实现和重写一下方法

    public CapabilitiesgetCapabilities()
    
    public StringglobalInfo()
    
    protected InstancesdetermineOutputFormat(Instances inputFormat)
    
    protected Instancesprocess(Instances inst)

    完整代码:

    @Override
    public CapabilitiesgetCapabilities() {
    Capabilities capabilities =super.getCapabilities();
    capabilities.enableAllAttributes();
    capabilities.enableAllClasses();
    capabilities.enable(Capability.NO_CLASS);
    return capabilities;
    }
    
    public StringglobalInfo() {
    return"A simple batch filter that adds an additional attribute 'bla' at the end " +"containing the index of the processed instance.";
    }
    
    protected InstancesdetermineOutputFormat(Instances inputFormat) {
    Instances result =new Instances(inputFormat,0);
    return result;
    }
    
    protected Instancesprocess(Instances inst) {
    Instances result =new Instances(determineOutputFormat(inst),0);
    for (int i =0; i < inst.numInstances(); i++) {
    double[] values =newdouble[result.numAttributes()];
    for (int n =0; n < inst.numAttributes(); n++) values[n] = Math.floor(inst.instance(i).value(n));
    result.add(new Instance(1, values));
    }
    return result;
    }

    效果:

    weka3_6