2009年02月10日

LRU算法的实现 什么是LRU算法? LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是

为虚拟页式存储管理服务的。自然,达到这样一种情形的算法是最理想的了—-每次调换出的页面是所有

内存页面中最迟将被使用的—-这可以最大限度的推迟页面调换,这种算法,被称为理想页面置换算法。

为了尽量减少与理想算法的差距,产生了各种精妙的算法,最近最少使用页面置换算法便是其中一个。当

然,LRU算法的缺点在于实现方法的不足—-效率高的硬件算法通常在大多数机器上无法运行,而软件算

法明显有太多的开销。

LFU实现比较困难,目前多用LRU进行页面替换

2)RAND、FIFO、LRU及OPT算法
  ·RAND算法:用软硬件的随面数产生主存中要被替换页的页号。
  ·FIFO算法:选择最早装入主存的页作为被替换的页。这种算法实现方便,但不一定正确反映出程序

的局部性。
  谁还记的《数据结构》的队列,哦,你对了,给你一个糖,队列就象排队买票,谁先排到队中,谁更

早滚蛋。
  ·LRU算法:选择近期最少访问的页作为被替换页。

        ·LFU算法:最近最不常用调度算法,是根据在一段时间里页面被使用的次数选择出最少使用的页
  大家要注意LRU和LFU两个算法的区别,从上边两种解决使用位都为1的方法来看,随机法接近于LRU,

第二种接近LFU,大家看看《操作系统》P76页,那写的清楚。
  ·OPT算法:根据未来实际使用情况将未来的近期里不用的页替换出去。这种算法是用来评价期它替

换算法好坏的标准。不可能实现。

2008年06月22日

作者:普元周进  来自:好友Qzone更新 6月17日 |  收藏 - 加标签

2007年11月20日

java调用C/C++的过程

最近在公司里做了一个手机的项目,需要JAVA程序在发送短信的时候和第三方的短信服务器连接。短信接口是用C++写的。琢磨了三天,大致搞懂了JNI的主体部分。先将心得整理,希望各位朋友少走弯路。首先引用一篇文章,介绍一个简单的JNI的调用的过程。JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决JAVA对本地操作的一种方法就是JNI。JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法。简单介绍及应用如下:
一、JAVA中所需要做的工作
在JAVA程序中,首先需要在类中声明所调用的库名称,如下:
static {
System.loadLibrary(“goodluck”);
}
在这里,库的扩展名字可以不用写出来,究竟是DLL还是SO,由系统自己判断。还需对将要调用的方法做本地声明,关键字为native。且只需要声明,而不需要具体实现。如下:
public native static void set(int i);
public native static int get();

  然后编译该JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就会生成C/C++的头文件。

  例如程序testdll.java,内容为:
public class testdll
{
static
{
System.loadLibrary("goodluck");
}
public native static int get();
public native static void set(int i);
public static void main(String[] args)
{
testdll test = new testdll();
test.set(10);
System.out.println(test.get());
}
}

  用javac testdll.java编译它,会生成testdll.class。
  再用javah testdll,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。

  二、C/C++中所需要做的工作
  对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现。然后编译连接成库文件即可。再把库文件拷贝到JAVA程序的路径下面,就可以用JAVA调用C/C++所实现的功能了。
  接上例子。我们先看一下testdll.h文件的内容:
/* DO NOT EDIT THIS FILE – it is machine generated */
#include
/* Header for class testdll */
#ifndef _Included_testdll
#define _Included_testdll
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: testdll
* Method: get
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);
/*
* Class: testdll
* Method: set
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif

  在具体实现的时候,我们只关心两个函数原型
  JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass); 和
  JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);

  这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使JAVA的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。

  好,下面我们用testdll.cpp文件具体实现这两个函数:
#include "testdll.h"
int i = 0;
JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)
{
return i;
}
JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j)
{
i = j;
}

  编译连接成库文件,本例是在WINDOWS下做的,生成的是DLL文件。并且名称要与JAVA中需要调用的一致,这里就是goodluck.dll 。把goodluck.dll拷贝到testdll.class的目录下,java testdll运行它,就可以观察到结果了。
    我的项目比较复杂,需要调用动态链接库,这样在JNI传送参数到C程序时,需要对参数进行处理转换。才可以被C程序识别。
      大体程序如下:
    public class SendSMS {
    static
    {
    System.out.println(System.getProperty("java.library.path"));
    System.loadLibrary("sms");
    }
    public native static int SmsInit();
    public native static int SmsSend(byte[] mobileNo, byte[] smContent);
    }
   
      在这里要注意的是,path里一定要包含类库的路径,否则在程序运行时会抛出异常:
      java.lang.UnsatisfiedLinkError: no sms in java.library.path
      at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1491)
      at java.lang.Runtime.loadLibrary0(Runtime.java:788)
      at java.lang.System.loadLibrary(System.java:834)
      at com.mobilesoft.sms.mobilesoftinfo.SendSMS.(SendSMS.java:14)
      at com.mobilesoft.sms.mobilesoftinfo.test.main(test.java:18)
      Exception in thread "main"
   
      指引的路径应该到.dll文件的上一级,如果指到.dll,则会报:
      java.lang.UnsatisfiedLinkError: C:\sms.dll: Can’t find dependent libraries
      at java.lang.ClassLoader$NativeLibrary.load(Native Method)
      at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1560)
      at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1485)
      at java.lang.Runtime.loadLibrary0(Runtime.java:788)
      at java.lang.System.loadLibrary(System.java:834)
      at com.mobilesoft.sms.mobilesoftinfo.test.main(test.java:18)
      Exception in thread "main"
   
      通过编译,生成com_mobilesoft_sms_mobilesoftinfo_SendSMS.h头文件。(建议使用Jbuilder进行编译,操作比较简单!)这个头文件就是Java和C之间的纽带。要特别注意的是方法中传递的参数jbyteArray,这在接下来的过程中会重点介绍。
    /* DO NOT EDIT THIS FILE – it is machine generated */
    #include
    /* Header for class com_mobilesoft_sms_mobilesoftinfo_SendSMS */
    #ifndef _Included_com_mobilesoft_sms_mobilesoftinfo_SendSMS
    #define _Included_com_mobilesoft_sms_mobilesoftinfo_SendSMS
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
    * Class: com_mobilesoft_sms_mobilesoftinfo_SendSMS
    * Method: SmsInit
    * Signature: ()I
    */
    JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsInit
    (JNIEnv *, jclass);
    /*
    * Class: com_mobilesoft_sms_mobilesoftinfo_SendSMS
    * Method: SmsSend
    * Signature: ([B[B)I
    */
    JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsSend
    (JNIEnv *, jclass, jbyteArray, jbyteArray);
    #ifdef __cplusplus
    }
    #endif
    #endif
   
      对于我要调用的C程序的动态链接库,C程序也要提供一个头文件,sms.h。这个文件将要调用的方法罗列了出来。
    /*
    * SMS API
    * Author: yippit
    * Date: 2004.6.8
    */
    #ifndef MCS_SMS_H
    #define MCS_SMS_H
    #define DLLEXPORT __declspec(dllexport)
    /*sms storage*/
    #define SMS_SIM 0
    #define SMS_MT 1
    /*sms states*/
    #define SMS_UNREAD 0
    #define SMS_READ 1
    /*sms type*/
    #define SMS_NOPARSE -1
    #define SMS_NORMAL 0
    #define SMS_FLASH 1
    #define SMS_MMSNOTI 2
    typedef struct tagSmsEntry {
    int index; /*index, start from 1*/
    int status; /*read, unread*/
    int type; /*-1-can’t parser 0-normal, 1-flash, 2-mms*/
    int storage; /*SMS_SIM, SMS_MT*/
    char date[24];
    char number[32];
    char text[144];
    } SmsEntry;
    DLLEXPORT int SmsInit(void);
    DLLEXPORT int SmsSend(char *phonenum, char *content);
    DLLEXPORT int SmsSetSCA(char *sca);
    DLLEXPORT int SmsGetSCA(char *sca);
    DLLEXPORT int SmsSetInd(int ind);
    DLLEXPORT int SmsGetInd(void);
    DLLEXPORT int SmsGetInfo(int storage, int *max, int *used);
    DLLEXPORT int SmsSaveFlash(int flag);
    DLLEXPORT int SmsRead(SmsEntry *entry, int storage, int index);
    DLLEXPORT int SmsDelete(int storage, int index);
    DLLEXPORT int SmsModifyStatus(int storage, int index); /*unread,read*/
    #endif
        在有了这两个头文件之后,就可以进行C程序的编写了。也就是实现对JNI调用的两个方法。在网上的资料中,由于调用的方法实现的都比较简单,(大多是打印字符串等)所以避开了JNI中最麻烦的部分,也是最关键的部分,参数的传递。由于Java和C的编码是不同的,所以传递的参数是要进行再处理,否则C程序是会对参数在编译过程中提出警告,例如;warning C4024: ’SmsSend’ : different types for formal and actual parameter 2等。
  Sms.c的程序如下:
#include "sms.h"
#include "com_mobilesoft_sms_mobilesoftinfo_SendSMS.h"
JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsInit(JNIEnv * env, jclass jobject)
{
return SmsInit();
}

JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsSend(JNIEnv * env, jclass jobject, jbyteArray mobileno, jbyteArray smscontent)
{
char * pSmscontent ;
//jsize theArrayLengthJ = (*env)->GetArrayLength(env,mobileno);
jbyte * arrayBody = (*env)->GetByteArrayElements(env,mobileno,0);
char * pMobileNo = (char *)arrayBody;
printf("[%s]
 ", pMobileNo);
 //jsize size = (*env)->GetArrayLength(env,smscontent);
 arrayBody = (*env)->GetByteArrayElements(env,smscontent,0);
 pSmscontent = (char *)arrayBody;
 printf("<%s>
 ", pSmscontent);
 return SmsSend(pMobileNo,pSmscontent);
 }
 
   对于C或C++,在程序上是会有稍微的不同,这可以由读者对其进行适当的修改。这里要注意的是GetArrayLength,GetByteArrayElements等这些JNI中已经包含的方法,这些方法是专门对转换参数类型而提供的。具体的方法有很多,在下一篇中会做专门的介绍。
   在完成了上述的文件后,可以对sms.c进行编译,生成.dll文件(建议在release中编译,这样动态链接库的容积会比较小!)
   完成.dll文件的编译后,就可以在Java中调用C程序中的方法了。例如文件test.java
 public class test {
 public test() {
 }
 public static void main(String[] args) {
 byte[] mobileno = {
 0×31, 0×33, 0×36, 0×36, 0×31, 0×36, 0×33, 0×30, 0×36, 0×36, 0×37, 0×00};
 String smscontentemp = "早上好";
 byte[] temp = {0};
 try {
 byte[] smscontentdb = smscontentemp.getBytes("gbk");
 byte[] smscontent = new byte[smscontentdb.length + temp.length];
 System.arraycopy(smscontentdb, 0, smscontent, 0, smscontentdb.length);
 System.arraycopy(temp, 0, smscontent, smscontentdb.length, temp.length);
 SendSMS sendSMS = new SendSMS();
 sendSMS.SmsInit();
 if (sendSMS.SmsSend(mobileno, smscontent) >= 0) {
 System.out.println("chenggong !");
 }
 else {
 System.out.println("shibai !");
 }
 }catch (Exception ex) {}
 }
 }
 
   在这个文件中要注意的有一点,就是在传递字节数组到C程序中时,最后的结尾一定要以0结束。这是一个偷懒的做法,不过是个有效的做法。因为大多数情况下,接口是由第三方提供的。所以我们一般是不知道在C的方法里,具体是怎么处理参数的。而C又是要求数组是有长度。所以,在Java中,如果你不想写程序传数组的长度,那么在数组中以0结尾就是最方便的方法了。当然,如果有更好的方法也希望大家提出。
 
   到这里,一个完整的Java通过JNI调用动态链接库的程序就完成了。实际上也不是很复杂。只要多注意一下细节,是很容易得出来的。

2007年11月01日

 

first see : http://fallenlord.blogdriver.com/fallenlord/1226332.html

DWR中取得session等信息

关键字:   DWR session request    

最近我们的项目决定采用Ajax技术实现一些功能,最后采用了DWR.在使用DWR的时候,遇到了要获取session中保存的用户信息的问题.上网查了一下资料,测试成功后简单记录起来.

在DWR中需要用到session,request等这些东西的时候,可以用以下方法获取:
1. 使用DWR的API (很多人都不推荐这种做法,经测试,使用起来肯定没问题)
WebContext ctx = WebContextFactory.get();
ctx.getSession()
ctx.getHttpServletRequest()

2. 在Java的服务方法中定义这些类型的参数,让DWR自动传入相应的对象:
HttpServletRequest,HttpServletResponse,HttpSession,ServletContext,ServletConfig.
示例如下:
Java端定义方法: saveOrder(String id, String name, HttpSession session)
Javascript调用: OrderService.saveOrder(jsID,jsName,callBack)
注意,这里不需要传入session这个参数,DWR会自动传入,在Java端可以直接使用.

http://xsen.javaeye.com/blog/62947

HttpSession session = WebContextFactory.get().getSession();
HttpServletResponse response = WebContextFactory.get().getHttpServletResponse();
HttpServletRequest request = WebContextFactory.get().getHttpServletRequest();

http://summernight.javaeye.com/blog/105718

2007年09月14日
什么是LRU算法? LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是为虚拟页式存储管理服务的。
关于操作系统的内存管理,如何节省利用容量不大的内存为最多的进程提供资源,一直是研究的重要方向。而内存的虚拟存储管理,是现在最通用,最成功的方式——在内存有限的情况下,扩展一部分外存作为虚拟内存,真正的内存只存储当前运行时所用得到信息。这无疑极大地扩充了内存的功能,极大地提高了计算机的并发度。虚拟页式存储管理,则是将进程所需空间划分为多个页面,内存中只存放当前所需页面,其余页面放入外存的管理方式。
然而,有利就有弊,虚拟页式存储管理减少了进程所需的内存空间,却也带来了运行时间变长这一缺点:进程运行过程中,不可避免地要把在外存中存放的一些信息和内存中已有的进行交换,由于外存的低速,这一步骤所花费的时间不可忽略。因而,采取尽量好的算法以减少读取外存的次数,也是相当有意义的事情。
对于虚拟页式存储,内外存信息的替换是以页面为单位进行的——当需要一个放在外存的页面时,把它调入内存,同时为了保持原有空间的大小,还要把一个内存中页面调出至外存。自然,这种调动越少,进程执行的效率也就越高。那么,把哪个页面调出去可以达到调动尽量少的目的?我们需要一个算法。
自然,达到这样一种情形的算法是最理想的了——每次调换出的页面是所有内存页面中最迟将被使用的——这可以最大限度的推迟页面调换,这种算法,被称为理想页面置换算法。可惜的是,这种算法是无法实现的。
为了尽量减少与理想算法的差距,产生了各种精妙的算法,最近最少使用页面置换算法便是其中一个。LRU算法的提出,是基于这样一个事实:在前面几条指令中使用频繁的页面很可能在后面的几条指令中频繁使用。反过来说,已经很久没有使用的页面很可能在未来较长的一段时间内不会被用到。这个,就是著名的局部性原理——比内存速度还要快的cache,也是基于同样的原理运行的。因此,我们只需要在每次调换时,找到最近最少使用的那个页面调出内存。这就是LRU算法的全部内容。
如何用具体的数据结构来实现这个算法?
首先,最容易想到,也最简单的方法:计时法。给页表中的每一页增加一个域,专门用来存放计时标志,用来记录该页面自上次被访问以来所经历的时间。页面每被访问一次,计时清0。要装入新页时,从内存的页面中选出时间最长的一页,调出,同时把各页的计时标志全部清0,重新开始计时。
计时法可以稍作改变,成为计数法:页面被访问,计数标志清0,其余所有内存页面计数器加1;要装入新页时,选出计数最大的一页调出,同时所有计数器清0。
这两种方法确实很简单,但运行效率却不尽如人意。每个时刻,或是每调用一个页面,就需要对内存中所有页面的访问情况进行记录和更新,麻烦且开销相当大。
另一种实现的方法:链表法。
操作系统为每个进程维护一条链表,链表的每个结点记录一张页面的地址。调用一次页面,则把该页面的结点从链中取出,放到链尾;要装入新页,则把链头的页面调出,同时生成调入页面的结点,放到链尾。
链表法可看作简单计时/计数法的改良,维护一个链表,自然要比维护所有页面标志要简单和轻松。可是,这并没有在数量级上改变算法的时间复杂度,每调用一个页面,都要在链表中搜寻对应结点并放至链尾的工作量并不算小。
 
以上是单纯使用软件实现的算法。不过,如果能有特殊的硬件帮忙,我们可以有更有效率的算法。
首先,如果硬件有一个64位的计数器,每条指令执行完后自动加1。在每个页表项里添加一个域,用于存放计数器的值。进程运行,每次访问页面的时候,都把计数器的值保存在被访问页面的页表项中。一旦发生缺页,操作系统检查页表中所有的计数器的值以找出最小的一个,那这一页就是最久未使用的页面,调出即可。
其次,另外一个矩阵算法:在一个有n个页框的机器中,LRU硬件可以维持一个n*n的矩阵,开始时所有位都是0。访问到第k页时,硬件把k行的位全设为1,之后再把k列的位置设为0。容易证明,在任意时候,二进制值最小的行即为最久未使用的页面,当调换页面时,将其调出。
以上的两种算法,无疑都要比纯粹的软件算法方便且快捷。每次页面访问之后的操作——保存计数器值和设置k行k列的值,时间复杂度都是O(1)量级,与纯软件算法不可同日而语。
那是否软件算法就毫无用处?当然不是,硬件算法有它致命的缺陷,那就是需要硬件的支持才能运行。如果机器上恰好有所需硬件,那无疑是再好不过;反之,若机器上没有这种硬件条件,我们也只能无奈地抛弃硬件算法,转而选取相对麻烦的软件算法了。
最后,让我们来谈论一下LRU算法。首先,这是一个相当好的算法,它是理想算法很好的近似。在计算机系统中应用广泛的局部性原理给它打造了坚实的理论基础,而在实际运用中,这一算法也被证明拥有极高的性能。在大规模的程序运行中,它产生的缺页中断次数已很接近理想算法。或许我们还能找到更好的算法,但我想,得到的收益与付出的代价恐怕就不成比例了。当然,LRU算法的缺点在于实现方法的不足——效率高的硬件算法通常在大多数机器上无法运行,而软件算法明显有太多的开销。与之相对的,FIFO算法,和与LRU相似的NRU算法,性能尽管不是最好,却更容易实现。所以,找到一个优秀的算法来实现LRU,就是一个非常有意义的问题。

 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1759793

2007年08月19日

一、概述
   
字符串在JavaScript中几乎无处不在,在你处理用户的输入数据的时候,在读取或设置DOM对象的属性时,在操作cookie时,当然还有更多JavaScript的核心部分提供了一组属性和方法用于通用的字符串操作,如分割字符串,改变字符串的大小写,操作子字符串等。
   
当前的大部分浏览器也能从强大的正则表达式获益,因为它极大地简化了大量的字符串操作任务,不过它也需要你克服一条有些陡峭的学习曲线。在这里,主要是介绍字符串本身的一些操作,正则表达式会在以后的随笔中涉及。

二、字符串的创建
   
创建一个字符串有几种方法。最简单的是用引号将一组字符包含起来,可以将其赋值给一个字符串变量。
    var myStr = "Hello, String!";
   
可以用双引号或单引号将字符串包含,但要注意,作为界定字符串的一对引号必须是相同的,不能混用。
   
var myString = "Fluffy is a pretty cat.’; 这样的声明就是非法的。
   
允许使用两种引号,使得某些操作变得简单,比如将一种嵌入另外一种:
    document.write("<img src=’img/logo.jpg’ height=’30′ width=’100′ alt=’Logo’>");

    我们在上面脚本创建了几个字符串,但本质上,它们并不是真正的字符串对象,准确地说,它们是字符串类型的值。要创建一个字符串对象,可使用如下语句:var strObj = new String("Hello, String!");
   
使用typeof运算符查看会发现,上面的myStr类型为string,而strObj类型为object

   
   
如果想知道字符串的长度,使用其length属性:string.length
   
得到字符串的指定位置的字符使用方法:string.charAt(index);

三、字符串的拼接
问题:
   
将两个或多个字符串拼接为一个大的字符串
解决方案:
   
非常简单,就用一个"+"将两个字符串"相加"
    var longString = "One piece " + "plus one more piece.";
   
要将多个字符串累积为一个字符串,还可以使用"+="操作符:
    var result = "";
    result += "My name is Anders"
    result += " and my age is 25";  
   
   
要在字符串中添加换行符,需要使用转义字符"\n"
    var confirmString = "You did not enter a response to the last " +
        "question.\n\nSubmit form anyway?";
    var confirmValue = confirm(confirmString);
   
但这种方法只能用在像警告、确认对话框之类的情况下,如果将这段文本作为HTML内容呈现,就无效了,此时用"<br>"代替它:
    var htmlString = "First line of string.<br>Second line of string.";
    document.write(htmlString);

    String对象还提供了方法concat(),它完成与"+"相同的功能:
    string.concat(value1, value2, …)
   
不过concat()方法显然不如"+"来得直观简洁。

四、访问字符串的子串
问题:
   
获得一字符串的一部分的副本。
解决方案:
   
使用substring()slice()方法(NN4+, IE4+),下面说明它们的具体用法。
    substring()
的原型为:  string.substring(from, to)
   
第一个参数from指定了子字符串在原字符串中的起始位置(基于0的索引);第二个参数to是可选的,它指定了子字符串在原字符串的结束位置(基于0的索引),一般情况下,它应比from大,如果它被省略,那么子字符串将一直到原字符串的结尾处。

   
如果参数from不小心比参数to大了会怎样?JavaScript会自动调解子字符串的起止位置,也就是说,substring()总是从两个参数中较小的那个开始,到较大的那个结束。不过要注意,它包含起始位置的那个字符,但不包含结束位置的那个字符。
    var fullString = "Every dog has his day.";
    var section = fullString.substring(0, 4); // section is "Ever".
    section = fullString.substring(4, 0);     // section is also "Ever".
    section = fullString.substring(1, 1);     // section is an empty string.
    section = fullString.substring(-2, 4); // section is "Ever", same as fullString.substring(0, 4);    slice()
的原型为:  string.slice(start, end)
   
参数start表示子串的起始位置,如果为负数,那么可以理解为倒数第几个开始,例如-3表示从倒数第三个开始;参数end表示结束位置,与start一样,它也可以为负数,其含义也表示到倒数第几个结束。slice()的参数可以为负数,所以要比substring()更加灵活,但没那么宽容了,如果startend要大,它将返回一个空字符串(示例略)

   
还有一个方法是substr(),其原型为: string.substr(start, length)
   
从原型可以看出它的参数的含义,start表示起始位置,length则表示子字符串的长度。JavaScript标准不提倡使用该方法。

五、字符串的大小写转换
问题:
   
在你的页面上有文本框接收用户的输入信息,比如城市,然后你会根据他的城市的不同做不同的处理,这时自然会用到字符串比较,那么在比较前,最好进行大小写转换,这样只要考虑转换后的情形即可;或者要在页面上收集数据,然后将这些数据存储在数据库,而数据库恰好只接收大写字符;在这些情况下,我们都要考虑对字符串进行大小写转换。
解决方案:
   
使用toLowerCase()toUpperCase()方法:
    var city = "ShanGHai";
    city = city.toLowerCase();  // city is "shanghai" now.
六、判断两个字符串是否相等
问题:
   
比如,你想拿用户的输入值与已知的字符串比较
解决方案:
   
先将用户的输入值全部转换为大写(或小写),然后再行比较:
    var name = document.form1.txtUserName.value.toLowerCase();
    if(name == "urname")
    {
        // statements go here.
    }
    JavaScript
有两种相等运算符。一种是完全向后兼容的,标准的"==",如果两个操作数类型不一致,它会在某些时候自动对操作数进行类型转换,考虑下面的赋值语句:
    var strA = "i love you!";
    var strB = new String("i love you!");
   
这两个变量含有相同的字符序列,但数据类型却不同,前者为string,后者为object,在使用"=="操作符时,JavaScript会尝试各种求值,以检测两者是否会在某种情况下相等。所以下面的表达式结果为true strA == strB
   
第二种操作符是"严格""===",它在求值时不会这么宽容,不会进行类型转换。所以表达式strA === strB的值为false,虽然两个变量持有的值相同。
   
有时代码的逻辑要求你判断两个值是否不相等,这里也有两个选择:"!="和严格的"!==",它们的关系就类似于"==""==="
讨论:
    "=="
"!="在求值时会尽可能地寻找值的匹配性,但你可能还是想在比较前进行显式的类型转换,以"帮助"它们完成工作。比如,如果想判断一个用户的输入值(字符串)是否等于一个数字,你可以让"=="帮你完成类型转换:
    if(document.form1.txtAge.value == someNumericVar) { … }
   
也可以提前转换:
    if(parseInt(document.form1.txtAge.value) == someNumericVar) { … }
   
如果你比较习惯于强类型的编程语言(比如C#,Java),那么这里你可以延续你的习惯(类型转换),这样也会增强程序的可读性。

    有一种情况需要注意,就是计算机的区域设置。如果用"<"">"来比较字符串,那么JavaScript把它们作为Unicode来比较,但显然,人们在浏览网页时不会把文本当作Unicode来阅读 :) 比如在西班牙语中,按照传统的排序,"ch"将作为一个字符排在"c""d"之间。localeCompare()提供了一种方式,可以帮助你使用默认区域设置下的字符排序规则。
    var strings;  //
要排序的字符串数组,假设已经得到初始化
    strings.sort(function(a,b) { return a.localeCompare(b) });  //
调用sort()方法进行排序

七、字符串的查找
问题:
   
判断一个字符串是否包含另一个字符串。
解决方案:
   
使用stringindexOf()方法:
    strObj.indexOf(subString[, startIndex])
    strObj
为要进行判断的字符串,subString为要在strObj查找的子字符串,startIndex是可选的,表示查找的开始位置(基于0的索引),如果startIndex省略,则从strObj开始处查找,如果startIndex小于0,则从0开始,如果startIndex大于最大索引,则从最大索引处开始。
    indexOf()
返回strObjsubString的开始位置,如果没有找到,则返回-1。在脚本中,可以这么使用:
    if(largeString.indexOf(shortString) != -1)
    {
        //
如果包含,进行相应处理;
    }
   
也许一个字符串会包含另一字符串不止一次,这时第二个参数startIndex也许会派上用场,下面这个函数演示如何求得一个字符串包含另外一个字符串的次数:
    function countInstances(mainStr, subStr)
    {
        var count = 0;
        var offset = 0;
        do
        {
            offset = mainStr.indexOf(subStr, offset);
            if(offset != -1)
            {
                count++;
                offset += subStr.length;
            }
        }while(offset != -1)
        return count;
    }
    String
对象有一个与indexOf()对应的方法,lastIndexOf()
    strObj.lastIndexOf(substring[, startindex])
    strObj
为要进行判断的字符串,subString为要在strObj查找的子字符串,startIndex是可选的,表示查找的开始位置(基于0的索引),如果startIndex省略,则从strObj末尾处查找,如果startIndex小于0,则从0开始,如果startIndex大于最大索引,则从最大索引处开始。该方法自右向左查找,返回subStringstrObj中最后出现的位置,如果没有找到,返回-1

八、在Unicode值和字符串中的字符间转换
问题:
   
获得一个字符的Unicode编码值,反之亦然。
解决方案:
   
要获得字符的Unicode编码,可以使用string.charCodeAt(index)方法,其定义为:
    strObj.charCodeAt(index)
    index
为指定字符在strObj对象中的位置(基于0的索引),返回值为065535之间的16位整数。例如:
    var strObj = "ABCDEFG";
    var code = strObj.charCodeAt(2); // Unicode value of character ‘C’ is 67
   
如果index指定的索引处没有字符,则返回值为NaN

    要将Unicode编码转换为一个字符,使用String.fromCharCode()方法,注意它是String对象的一个"静态方法",也就是说在使用前不需要创建字符串实例:
    String.fromCharCode(c1, c2, …)
   
它接受0个或多个整数,返回一个字符串,该字符串包含了各参数指定的字符,例如:
    var str = String.fromCharCode(72, 101, 108, 108, 111);  // str == "Hello"
讨论:
Unicode
包含了这个世界上很多书写语言的字符集,但别因为Unicode包含一个字符就期望这个字符能够在警告对话框、文本框或页面呈现时正常显示。如果字符集不可用,在页面将显示为问号或其它符号。一台典型的北美的计算机将不能在屏幕上显示中文字符,除非中文的字符集及其字体已经安装。

    参考:
    JavaScript And Dhtml Cookbook(Oreilly)      ;
    JavaScript-The Definitive Guide(4th Edition);

 

 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1729370

2007年08月09日

一种通用的输入校验方法和气球泡提示的实现(键盘用户界面模块)

选择自 huijunzi 的 Blog
 发布时间: 2004-12-19 09:52:47  来源/作者:csdn

 
键盘用户界面模块使用说明
 
1.       键盘用户界面模块介绍
健盘用户界面模块是一个处理WEB编程中常用的针对健盘用户界面交互功能的通用javascript模块,主要功能有输入强制性验证,回车切换输入域,快捷键执行功能按钮或切换输入域,输入域活动提示,友好提示信息显示等主要功能。
2.       模块所处位置与调用说明
该模块处在:defaultroot/platform/js/UiKey.js
调用方式为:
<script src="/defaultroot/platform/js/UiKey.js "></script>
该名必须必须放在</body>标签的前一句
提交前验证:
function SubmitForm(form)
{
    if(!checkFormInput(form)) return false;
    form.submit();
}

3.       功能介绍与实现说明
l         输入强制性验证
比如有如下输入框,该输入框只能输入数字字符,用如下方式声明
<input type="text" name="credNumber" minlength="5" maxlength="16" charset="Number" datatype="Cardnumber" nullable="true" size="40" tabindex="9" value="">
charset=”Number”属性就能定义该输入框所能输入的字符类型
注意:其实在实现上,该例子模块会自动调用isNumber(handle,keyCode)来进行验证,系统默认提供了几个验证函数,当需要其它验证方式时,可以自己定义相关的验证函数来进行验证
比如,我有一个输入框,需要输入IP地址,则可以如下声明:
Number:<input type="text" name="credNumber" minlength="5" maxlength="16" charset="Ip" datatype="Cardnumber" nullable="true" size="40" tabindex="9" value="">
然后实现isIP(handle,keyCode)函数即可纳入统一的验证框架之下
本验证只实现输入过程中的验证,至于输入完后格式正确性的验证由如下实现:
<input type="text" name="credNumber" minlength="5" maxlength="16" charset="Number" datatype="Cardnumber" nullable="true" size="40" tabindex="9" value="">
datetype=”Cardnumber”属性就能定义该输入框所需要输入的数据类型
注意:其实在实现上,该例子模块会自动调用isCardnumber(handle)来进行验证,系统默认提供了几个验证函数,当需要其它验证方式时,可以自己定义相关的验证函数来进行验证
比如,我有一个输入框,需要输入移动电话地址,则可以如下声明:
Number:<input type="text" name="Phone" minlength="5" maxlength="16" charset="Number" datatype="Mobile" nullable="true" size="40" tabindex="9" value="">
然后实现isMobile(handle)函数(其实已经实现)即可纳入统一的验证框架之下
l         回车切换输入域
一般情况下,用户在有多输入域的时候都希望在敲下回车后切换到下一输入域,本模块以统一的方式实现了,并且能够识别普通输入域与按钮(包括图片按钮,注意,只要图片有onclick事件,则认为是按钮),在按钮上敲回车将会执行该按钮功能。
要实现该功能,只要定义输入的域tabindex属性即可,如下所示
Number:<input type="text" id="test1" charset="Number" tabindex=1>
<p>
Visible:<input type="text" id="test5" charset="Visible" tabindex=2>
<p>
<IMG SRC="D:/eclipse/workspace/PFE/defaultroot/style/tempstylefolder/images/3_ico_3.gif" border="5" WIDTH="48" HEIGHT="40" BORDER="0" charset="ddd" accessKey="Z" onclick="alert(‘image1 click’);" tabindex=3 >
<INPUT TYPE="button" accessKey="5" value="(1)" onclick="alert(‘button click’);" tabindex=4>
如果一路按回车键,则焦点会按tabindex的顺序往下跳,在图片按钮与普通按钮上则不回跳,直接执行onclcik事件
l         快捷键功能
本模块能够定义各页面元素的快捷键,包括图片按钮,普通按钮,各输入域,其定义方式为设置对象的accessKey属性,如下所示
Number:<input type="text" id="test1" charset="Number" tabindex=1 accessKey=”1”>
<p>
Visible:<input type="text" id="test5" charset="Visible" tabindex=2 accessKey=”2”>
<p>
<IMG SRC="D:/eclipse/workspace/PFE/defaultroot/style/tempstylefolder/images/3_ico_3.gif" border="5" WIDTH="48" HEIGHT="40" BORDER="0" charset="ddd" accessKey="Z" onclick="alert(‘image1 click’);" tabindex=3 >
<INPUT TYPE="button" accessKey="5" value="(1)" onclick="alert(‘button click’);" tabindex=4>
当按下ALT+1或者ALT+2后,第一个输入框和第二个输入框会得到焦点
当按下ALT+z或者ALT+5时,图片的onclick事件与按钮的onclick事件会执行
本模块模认定义home键将焦点落在第一个输入域上,end键将焦点落在最后一个输入区域上
l         输入域活动提示
本模块会自动完成,当某一个输入域获得焦点时,会加重显示该输入域,当文本输入域
获得焦点时会自动选择其所有文本
l         友好提示信息
信息提示一直采用alert的方式,这种方式不友好,用户要点击确定后才能继续进行下去,本模块提供汽球型友好提示方式,调用方式如下:
showTip(handle,”必须输入用户名!”);
handle为输入框的句柄
注意,为了显示对应的汽泡提示,还有几个对应的小图片,可以自己帮,也可以找我要!
如果要用在struts 标签库中也是可以的,不过要改一下标签库,如果有需要的也可以直接联系我!
QQ:6045306
EMAIL:huijunzi@21cn.com
//以下为代码
/*
说明:文本框输入格式验证与气球提示实现,图片快捷键功能实现
版权:Copyright (C) 2004 Cyril
作者:Cyril
调用方式:
<script src="UIKey.js"></script>
必须放在</body>标签的前一句
*/
//初始化调用
//先提示画层
drawTipDiv();
//输出样式表
drawStyle();
//装载侦听器
addListener();
//容错处理
function killErrors() {
return true;
}
//window.onerror = killErrors;
//================以下为系统函数区=======================//
//全局变量区
var oldInputStyle;
var oldImgStyle;
var firstInput;
var endInput;
var timer;
//显示提示信息层
function showTip(handle,msg) {
    //alert(handle.type);
    handle.focus();   
 var pos = getPosition(handle);
 var t = pos.top;
 var l = pos.left;
 document.all.checkMsgDiv.style.left=l-10+getTextLength(handle);
    document.all.checkMsgDiv.style.top=t+handle.clientHeight;
    document.all.checkMsgTd.innerHTML=msg;
 document.all.checkMsgDiv.style.visibility = ‘visible’;
 //隐藏被层遮挡的选择框
 HideOverSels("checkMsgDiv");
 timer = setTimeout("hideTip();", 2500);
 return false;
}
//表单校验函数
function checkFormInput(handle) {
  var controlList = handle.elements;
  var controlObj;
  for(var i=0;i<controlList.length;i++) {
   //如果是text控件,需要进行数据校验
   controlObj = controlList[i];
   if(isControlVisible(controlObj)) {
    if(controlObj.type==’text’ || controlObj.type==’password’) {
     //如果不充许为空,则需要判断
           if((controlObj.nullable=="false") && (controlObj.value=="")) {
    hideTip();
    showTip(controlObj,"此输入域不能为空!");
    return false;
     }
     //如果有最小长度限制,则需要判断
     if(controlObj.value!=” && controlObj.minlength!=null) {
     var realLength = controlObj.value.length;
     var needLength = controlObj.minlength;
              if(realLength<needLength) {
                 hideTip();
     showTip(controlObj,"此输入域至少需要"+needLength+"个字符!");
     return false;
     }
     }
     //判断数据的类型,调用相关的数据校验函数
     if(controlObj.datatype!=null && controlObj.value!=”) {
          var typeStr = controlObj.datatype.toLowerCase();
          var firstChar = typeStr.substring(0,1);
          firstChar = firstChar.toUpperCase();
          typeStr = firstChar+typeStr.substring(1,typeStr.length);
          var tempMsg=eval("is"+typeStr+"(controlObj);");
          if (tempMsg!=true)
          {
       hideTip();
          showTip(controlObj,"此输入域"+tempMsg);
       return false;
          }
     }
    }
   }
  }
  return true;
}
//系统调用接口
function handleKeyDown(event) {
  //有按键就要关闭tip层
  hideTip();
  //home键与end键定位第一个与最后一个输入域上
  if(event.srcElement.type!="text" && event.srcElement.type!="textarea" && event.keyCode==36) {
   if(firstInput) firstInput.focus();
  }
  if(event.srcElement.type!="text" && event.srcElement.type!="textarea" && event.keyCode==35) {
   if(endInput) endInput.focus();
  }
  //处理回车切换焦点以及按钮与图片执行功能
  if(event.keyCode==13 && event.srcElement.type!="button" && event.srcElement.type!="reset" && event.srcElement.type!="" && event.srcElement.type!="textarea") {
   if(event.srcElement.src) {
    if(event.srcElement.onclick) {
    event.srcElement.fireEvent("onclick")
    return;
    } else {
    event.keyCode=9;
    return;
    }
   } else {
    event.keyCode=9;
    return;
   }
  }
  //处理图片按钮的快捷键
  if(event.altKey && event.keyCode!=18) {
   var shortKey=String.fromCharCode(event.keyCode);
   var quickKey = "";
      for(var i=0;i<document.images.length;i++) {
          quickKey = document.images[i].accessKey;
          quickKey = quickKey.toUpperCase();
    if(quickKey==shortKey) {
     if(document.images[i].onclick) {
         document.images[i].fireEvent("onclick");
         break;
     }
    }
   }
   //处理输入对象快捷方式
   var inputList = document.body.getElementsByTagName("INPUT");
      for(var i=0;i<inputList.length;i++) {
        quickKey = inputList[i].accessKey;
        quickKey = quickKey.toUpperCase();
  if(quickKey==shortKey) {
    inputList[i].focus();
        break;
  }
      }
   return;
  }
  if(event.srcElement.type==’text’ && event.srcElement.charset!=null) {
    //alert(event.srcElement.charset);
 if((event.keyCode>48 && event.keyCode<112) || (event.keyCode>127 && event.keyCode!=144))  checkInputChar(event.srcElement,event.keyCode);
  }
}
//有效性判断入口
function checkInputChar(handle,keyCode) {
    hideTip();
 var typeStr = handle.charset.toLowerCase();
 var firstChar = typeStr.substring(0,1);
 firstChar = firstChar.toUpperCase();
 typeStr = firstChar+typeStr.substring(1,typeStr.length);
 var tempMsg=eval("input"+typeStr+"(handle,keyCode);");
 if (tempMsg!=true)
 {
  hideTip();
  showTip(handle,tempMsg);
 }
}
//关闭提示信息层
function hideTip() {
  document.all.checkMsgDiv.style.visibility = ‘hidden’;
  //显示被隐藏了的选择框
  ShowOverSels("checkMsgDiv");
  clearTimeout(timer);
}
//获得文本框中文本的象素单位的宽度
function getTextLength(handle)
{
    var range = handle.createTextRange();
    return range.boundingWidth;
    //return 0;
}
//画一个隐藏的层
function drawTipDiv() {
  document.write("<div id=\"checkMsgDiv\"  style=\"position:absolute; width:218px; overflow: visible; z-index:1; visibility:hidden; left: 103px; top: 69px; height: 66px; border: 1px none #000000;\"> ");
  document.write("  <table width=\"218\" height=\"65\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"  id=\"checkMsgTable\">");
  document.write("    <tr> ");
  document.write("      <td height=\"13\" valign=\"top\"><img src=\"/platform/js/t_top.gif\" width=\"218\" height=\"26\"></td>");
  document.write("    </tr>");
  document.write("    <tr> ");
  document.write("      <td height=\"42\" valign=\"top\" background=\"/platform/js/t_bg.gif\">");
  document.write("  <table width=\"95%\" border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" style=\"font:9pt 宋体;\">");
  document.write("          <tr>");
  document.write("            <td id=\"checkMsgTd\">sdafs </td>");
  document.write("          </tr>");
  document.write("        </table></td>");
  document.write("    </tr>");
  document.write("    <tr>");
  document.write("      <td height=\"10\" valign=\"bottom\"><img src=\"/platform/js/t_bottom.gif\" width=\"218\" height=\"10\"></td>");
  document.write("    </tr>");
  document.write("  </table>");
  document.write("</div>");
}
//输出样式表
function drawStyle() {
  document.write("<style type=\"text/css\">");
  document.write("input.activeInput{border-top-color:#0000CC;border-top-width:1px;border-bottom-color:#0000CC;border-bottom-width:1px;border-left-color:#0000CC;border-left-width:1px;border-right-color:#0000CC;border-right-width:1px;}");
  document.write("img.activeImg{border-top-color:#3366FF;border-top-width:1px;border-bottom-color:#3366FF;border-bottom-width:1px;border-left-color:#3366FF;border-left-width:1px;border-right-color:#3366FF;border-right-width:1px;}");
  document.write("</style>");
}
//控件onFocus事件的侦听器
function onInputFocus() {
  if(window.event.srcElement.src) {
 if(window.event.srcElement.onclick) {
 oldImgStyle = window.event.srcElement.style;
    window.event.srcElement.className="activeImg";
 }
  } else {
 oldInputStyle = window.event.srcElement.style;
 window.event.srcElement.className="activeInput";
 if(window.event.srcElement.select) window.event.srcElement.select();
  }
}
//控件onblur事件的侦听器
function onInputBlur() {
  if(window.event.srcElement.src) {
    window.event.srcElement.className = "";
  } else {
    window.event.srcElement.className = "";
  }
}
//控件onkeypress事件的侦听器
function onInputKeydown () {
  handleKeyDown(window.event);
}
//控件onPaste事件的侦听器
function onInputPaste () {
 return false;
}
//表单onSubmit事件的侦听器
function onFormSubmit () {
  return checkFormInput(window.event.srcElement);
}
//控件onMouseover事件的侦听器
function onInputMouseover () {
  onInputFocus(); 
}
//控年onMouseout事件的侦听器
function onInputMouseout () {
  onInputBlur();
}
//为每个可输入控件装载侦听器
function addListener() {
 var inputList = document.body.getElementsByTagName("INPUT");
 if(inputList[0]) firstInput = inputList[0];
    for(var i=0;i<inputList.length;i++) {
   inputList[i].attachEvent (‘onkeydown’, onInputKeydown);
   inputList[i].attachEvent (‘onfocus’, onInputFocus);
   inputList[i].attachEvent (‘onblur’, onInputBlur);
   //inputList[i].attachEvent (‘onpaste’, onInputPaste);
   inputList[i].attachEvent (‘onmouseover’, onInputMouseover);
   inputList[i].attachEvent (‘onmouseout’, onInputMouseout);
   }
   if(inputList[i-1]) endInput = inputList[i-1];
   var inputList = document.body.getElementsByTagName("IMG");
   for(var i=0;i<inputList.length;i++) {
   inputList[i].attachEvent (‘onkeydown’, onInputKeydown);
   inputList[i].attachEvent (‘onfocus’, onInputFocus);
   inputList[i].attachEvent (‘onblur’, onInputBlur);
   }
   document.body.attachEvent(‘onkeydown’, onInputKeydown);
   var formList = document.body.getElementsByTagName("FORM");
   for(var i=0;i<formList.length;i++) {
   formList[i].attachEvent (‘onsubmit’,onFormSubmit);
   }
}
// 隐藏被ID为objID的对象(层)遮挡的所有select
function HideOverSels(objID)
{
    var sels = document.getElementsByTagName(’select’);
    for (var i = 0; i < sels.length; i++)
      if (Obj1OverObj2(document.all[objID], sels[i]))
        sels[i].style.visibility = ‘hidden’;
}
// 显示被ID为objID的对象(层)遮挡的所有select
function ShowOverSels(objID)
{
    var sels = document.getElementsByTagName(’select’);
    for (var i = 0; i < sels.length; i++)
      if (Obj1OverObj2(document.all[objID], sels[i]))
        sels[i].style.visibility = ‘visible’;
}
//判断obj1是否遮挡了obj2
function Obj1OverObj2(obj1, obj2)
{
  var pos1 = getPosition(obj1)
  var pos2 = getPosition(obj2)
  var result = true;
  var obj1Left = pos1.left – window.document.body.scrollLeft;
  var obj1Top = pos1.top – window.document.body.scrollTop;
  var obj1Right = obj1Left + obj1.offsetWidth;
  var obj1Bottom = obj1Top + obj1.offsetHeight;
  var obj2Left = pos2.left – window.document.body.scrollLeft;
  var obj2Top = pos2.top – window.document.body.scrollTop;
  var obj2Right = obj2Left + obj2.offsetWidth;
  var obj2Bottom = obj2Top + obj2.offsetHeight;
  if (obj1Right <= obj2Left || obj1Bottom <= obj2Top ||
      obj1Left >= obj2Right || obj1Top >= obj2Bottom)
    result = false;
  return result;
}
// 获取对象的坐标
function getPosition(Obj)
{
    var sumTop=0;
    var sumLeft=0;   
    while(Obj!=window.document.body) {
      sumTop+=Obj.offsetTop;
      if(Obj.tagName.toLowerCase()==’div’) {
        sumTop-=Obj.scrollTop;
      }
      sumLeft+=Obj.offsetLeft;
      Obj=Obj.offsetParent;
    }
 return {left:sumLeft,top:sumTop}
}
//判断控件的可见性
function isControlVisible(handle) {
  var retValue = true;
  while(handle.tagName.toLowerCase()!=’form’ && handle.style.display.toLowerCase()!=’none’) {
    handle = handle.parentElement;
  }
  if(handle.style.display==’none’) retValue = false;
  return retValue;
}
//================以上为系统函数区=======================//
//以下为输入过程中输入内容即时验证函数
//必须输入是数字
function inputNumber(handle,keyCode) {
  if(!((keyCode>=48&&keyCode<=57)||(keyCode>=96&&keyCode<=105))) {
 window.event.returnValue=false;
 return "必须输入数字!即如下字符:<br>1234567890";
  } else return true;
}
//必须输入字母
function inputLetter(handle,keyCode) {
  if(!((keyCode>=97&&keyCode<=122)||(keyCode>=65&&keyCode<=90))) {
 window.event.returnValue=false;
 return "必须输入大小写字母!即如下字符:<br>abcdefghijklmnopqrstuvwxyz<br>ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  } else return true;
}
//必须输入所有可见字符
function inputVisible(handle,keyCode) {
 var pattern = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.@><,-[]{}?/+=|\\\’\":;~!#$%()`";
 var keyValue=String.fromCharCode(keyCode);
 if(keyCode==190) keyValue = ".";
 if(keyCode==189) keyValue = "-";
 if(keyCode==188) keyValue = "<";
 if(keyCode==219) keyValue = "[";
 if(keyCode==221) keyValue = "]";
 if(keyCode==191) keyValue = "?";
 if(keyCode==187) keyValue = "+";
 if(keyCode==220) keyValue = "|";
 if(keyCode==222) keyValue = "’";
 if(keyCode==186) keyValue = ";";
 if(keyCode==192) keyValue = "~";
 if(pattern.indexOf(keyValue)!=-1) {
  window.event.returnValue=true;
  return true;
 }else{
  window.event.returnValue=false;
  return "必须输入可见字符!即如下字符:<br>ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>abcdefghijklmnopqrstuvwxyz<br>0123456789.@><,-[]{}?/+=|\\\’\":<br>;~!#$%()`";
 }
}
//必须输入字母与数字
function inputNormal(handle,keyCode) {
 var pattern = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
 var keyValue=String.fromCharCode(keyCode);
 if(pattern.indexOf(keyValue)!=-1) {
  window.event.returnValue=true;
  return true;
 }else{
  window.event.returnValue=false;
  return "必须输入可见字符!即如下字符:<br>ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>abcdefghijklmnopqrstuvwxyz<br>0123456789";
 }
}
//================以下为校验函数区=======================//
//函数名说明:is+TypeName,TypeName首字母大写
//参数handle为当前控件句柄
//参数keyCode为当前按钮的值
//返回说明:通过返回"",不通过返回不通过的原因描述
/*格式支持例表
格式字符           格式描述       格式说明
Number             数字型
Userid             用户ID
Username           用户名称
Enterprisename     企业单位名称
Loginname          登录名称
Cardnumber         证件号码
Address            地址
Phone              电话号码
Mobile             手机号码
Postcode           邮政编码
Email              电子邮件
Namesimplicity     姓名简拼
Password           密码
Namestr            名称字符串
DescStr            描述字符串
Pageurl            页面URL
Dirctory           磁盘路径
*/
//判断是否是数字
 function isNumber(handle){
  var pattern = /^(\d){1,14}$/;
    if (!pattern.exec(handle.value)) return "必须输入数字!";
    return true;
 }
//判断是否是用户账号
 function isUserid(handle){
  var pattern = /^(\d|\w){3,14}$/;
    if (!pattern.exec(handle.value)) return "必须输入数字<br>且长度需大于等于3位小于等于14位!";
    return true;
 }
//判断是否用户名称可以是字母也可以是中文
 function isUsername(handle){
  var pattern = /^[a-zA-Z\u4E00-\u9FA5]{2,50}$/;
    if (!pattern.exec(handle.value)) return "必须是中文字母或者数字<br>且长度需大于等于2位小于等于50位!"
    return true;
    }
//判断是否是企业名称:可以是字母 数字 中文 – _
    function isEnterprisename(handle){
        var pattern = /^[a-zA-Z0-9-_\u4E00-\u9FA5]{2,200}$/;
        if (!pattern.exec(handle.value)) return "必须是中文字母或者数字<br>且长度需大于等于2位小于等于200位!";
        return true;
    }
//判断是否是登录名称
    function isLoginname(handle){
        var pattern = /^([a-z]|[A-Z]|[0-9]){2,25}$/;
        if (!pattern.exec(handle.value)) return "必须是字母或者数字<br>且长度需大于等于2位小于等于25位!";
        return true;
 }
//判断是否是证件号码
 function isCardnumber(handle){
   var pattern;
  pattern = /^(\d){5,18}$/;
   if (!pattern.exec(handle.value)) return "必须是数字<br>且长度需大于等于5位小于等于16位!";
   return true;
 }
//地址
 function isAddress(handle){
  var pattern = /^[a-zA-Z0-9\u4E00-\u9FA5]{2,200}$/;
    if (!pattern.exec(handle.value)) return "必须是中文字母或者数字<br>且长度需大于等于2位小于等于200位!";
    return true;
 }
//联系电话
 function isPhone(handle){
  var pattern = /^(\d){6,30}$/;
    if (!pattern.exec(handle.value)) return "必须是数字<br>且长度需大于等于6位小于等于30位!";
    return true;
 }
//手机
 function isMobile(handle){
  var pattern = /^[1][3](\d){9}$/;
    if (!pattern.exec(handle.value)) return "必须是数字<br>且首两位是13长度是11位!";
    return true;
 }
//邮编
 function isPostcode(handle){
  var pattern = /^(\d){6}$/;
    if (!pattern.exec(handle.value)) return "必须是数字<br>且长度需是6位!";
    return true;
 }
//email
 function isEmail(handle){
  var pattern = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/;
    if (!pattern.exec(handle.value)) return "必须符合电子邮件地址格式";
    return true;
 }
//简拼
 function isNamesimplicity(handle){
  var pattern = /^([a-zA-Z]){2,25}$/;
    if (!pattern.exec(handle.value)) return "必须是字母<br>且长度需大于等于2位小于等于25位!";
    return true;
 }
//密码
 function isPassword(handle){
  var pattern = /^([a-zA-Z]|[0-9]){2,25}$/;
    if (!pattern.exec(handle.value)) return "必须是字母或者数字<br>且长度需大于等于2位小于等于25位!";
    return true;
 }
//判断是否是名称:可以是字母 数字 中文 – _
    function isNamestr(handle){
        var pattern = /^[a-zA-Z0-9-_\u4E00-\u9FA5]{1,40}$/;
        if (!pattern.exec(handle.value)) return "必须是中文字母或者数字<br>且长度需大于等于1位小于等于40位!";
        return true;
    }
//判断是否是描述信息:可以是字母 数字 中文 – _ , .
    function isDescstr(handle){
        var pattern = /^[a-zA-Z0-9-_,.\u4E00-\u9FA5]{1,50}$/;
        if (!pattern.exec(handle.value)) return "必须是中文字母或者数字<br>且长度需大于等于1位小于等于50位!";
        return true;
    }
//页面URL
    function isPageurl(handle){
        var pattern = /^[a-zA-Z0-9-_,./\u4E00-\u9FA5]{1,80}$/;
        if (!pattern.exec(handle.value)) return "必须是中文字母或者数字<br>且长度需大于等于`位小于等于80位!";
        return true;
    }
//目录路径
    function isDirctoryurl(handle){
        var pattern = /^[a-zA-Z0-9-_,.\\u4E00-\u9FA5]{1,300}$/;
        if (!pattern.exec(handle.value)) return "必须是中文字母或者数字<br>且长度需大于等于1位小于等于300位!";
        return true;
    }

/*
//高强度身份号码验证
var aCity={11:"北京",12:"天津",13:"河北",14:"山西",15:"内蒙古",21:"辽宁",22:"吉林",23:"黑龙江",31:"上海",32:"江苏",33:"浙江",34:"安徽",35:"福建",36:"江西",37:"山东",41:"河南",42:"湖北",43:"湖南",44:"广东",45:"广西",46:"海南",50:"重庆",51:"四川",52:"贵州",53:"云南",54:"西藏",61:"陕西",62:"甘肃",63:"青海",64:"宁夏",65:"新疆",71:"台湾",81:"香港",82:"澳门",91:"国外"}
function cidInfo(sId){
 var iSum=0
 var info=""
 if(!/^\d{17}(\d|x)$/i.test(sId))return false;
 sId=sId.replace(/x$/i,"a");
 if(aCity[parseInt(sId.substr(0,2))]==null)return "Error:非法地区";
 sBirthday=sId.substr(6,4)+"-"+Number(sId.substr(10,2))+"-"+Number(sId.substr(12,2));
 var d=new Date(sBirthday.replace(/-/g,"/"))
 if(sBirthday!=(d.getFullYear()+"-"+ (d.getMonth()+1) + "-" + d.getDate()))return "Error:非法生日";
 for(var i = 17;i>=0;i –) iSum += (Math.pow(2,i) % 11) * parseInt(sId.charAt(17 – i),11)
 if(iSum%11!=1)return "Error:非法证号";
 return aCity[parseInt(sId.substr(0,2))]+","+sBirthday+","+(sId.substr(16,1)%2?"男":"女")
}
document.write(cidInfo("380524198002300016"),"<br/>");
document.write(cidInfo("340524198002300019"),"<br/>")
document.write(cidInfo("340524197711111111"),"<br/>")
document.write(cidInfo("34052419800101001x"),"<br/>");
function isip(s){
 var check=function(v){try{return (v<=255 && v>=0)}catch(x){return false}};
 var re=s.split(".")
 return (re.length==4)?(check(re[0]) && check(re[1]) && check(re[2]) && check(re[3])):false
}
var s="202.197.78.129";
alert(isip(s))*/
//================以上为校验函数区=======================//

2006年11月24日

 Linux驱动入门

内核版本: 2.4.22
阅读此文的目的: 学会编写Linux设备驱动。
阅读此文的方法: 阅读以下2个文件: hello.c,asdf.c。
此文假设读者:
已经能用C语言编写Linux应用程序,
理解"字符设备文件, 块设备文件, 主设备号, 次设备号",
会写简单的Shell脚本和Makefile。

1. "hello.c"
——————————–
/*
* 这是我们的第一个源文件,
* 它是一个可以加载的内核模块,
* 加载时显示"Hello,World!",
* 卸载时显示"Bye!"。

* 需要说明一点,写内核或内核模块不能用写应用程序时的系统调用或函数库,
* 因为我们写的就是为应用程序提供系统调用的代码。

* 内核有专用的函数库,如<linux/kernel.h>, <linux/fs.h>, <linux/sche.h>等,
* 现在还没必要了解得很详细,
* 这里用到的printk的功能类似于printf。

* "/usr/src/linux"是你实际的内核源码目录的一个符号链接,
* 如果没有现在就创建一个,因为下面和以后都会用到。

* 编译它用"gcc -c -I/usr/src/linux/include hello.c",
* 如果正常会生成文件hello.o,

* 加载它用"insmod hello.o",
* 只有在文本终端下才能看到输出。

* 卸载它用"rmmod hello"
*/

/*
* 小技巧: 在用户目录的.bashrc里加上一行:
* alias mkmod=’gcc -c -I/usr/src/linux/include’
* 然后重新登陆Shell,
* 以后就可以用"mkmod hello.c"的方式来编译内核模块了。
*/

/* 开始例行公事 */
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif

#include <linux/config.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");
#ifdef CONFIG_SMP
#define __SMP__
#endif
/* 结束例行公事 */

#include <linux/kernel.h> /* printk()在这个文件里 */

static int
init_module
(){
printk("Hello,World!\n");
return 0; /* 如果初始工作失败,就返回非0 */
}

static void
cleanup_module
(){
printk("Bye!\n");
}
————————————

2. "asdf.c"
————————————
/*
* 这个文件是一个内核模块。
* 内核模块的编译,加载和卸载在前面已经介绍了。

* 这个模块的功能是,创建一个字符设备。
* 这个设备是一块4096字节的共享内存。
* 内核分配的主设备号会在加载模块时显示。
*/

/* 开始例行公事 */
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif

#include <linux/config.h>
#include <linux/module.h>

#ifdef CONFIG_SMP
#define __SMP__
#endif
MODULE_LICENSE("GPL");
/* 结束例行公事 */

#include <asm/uaccess.h> /* copy_to_user(), copy_from_user */
#include <linux/fs.h> /* struct file_operations, register_chrdev(), … */
#include <linux/kernel.h> /* printk()在这个文件里 */
#include <linux/sched.h> /* 和任务调度有关 */
#include <linux/types.h> /* u8, u16, u32 … */

/*
* 关于内核功能库,可以去网上搜索详细资料,
*/

/* 文件被操作时的回调功能 */
static int asdf_open (struct inode *inode, struct file *filp);
static int asdf_release (struct inode *inode, struct file *filp);
static ssize_t asdf_read (struct file *filp, char *buf, size_t count,loff_t *f_pos);
static ssize_t asdf_write (struct file *filp, const char *buf, size_t count,loff_t *f_pos);
static loff_t asdf_lseek (struct file * file, loff_t offset, int orig);

/* 申请主设备号时用的结构, 在linux/fs.h里定义 */
struct file_operations asdf_fops = {
open: asdf_open,
release: asdf_release,
read: asdf_read,
write: asdf_write,
llseek: asdf_lseek,
};

static int asdf_major; /* 用来保存申请到的主设备号 */
static u8 asdf_body[4096]="asdf_body\n"; /* 设备 */

static int
init_module
(){
printk ("Hi, This’ A Simple Device File!\n");
asdf_major = register_chrdev (0, "A Simple Device File", &asdf_fops); /* 申请字符设备的主设备号 */
if (asdf_major < 0) return asdf_major; /* 申请失败就直接返回错误编号 */
printk ("The major is:%d\n", asdf_major); /* 显示申请到的主设备号 */
return 0; /* 模块正常初始化 */
}

static void
cleanup_module
(){
unregister_chrdev(asdf_major, "A Simple Device File"); /* 注销以后,设备就不存在了 */
printk("A Simple Device has been removed,Bye!\n");
}

/*
* 编译这个模块然后加载它,
* 如果正常,会显示你的设备的主设备号。
* 现在你的设备就建立好了,我们可以测试一下。
* 假设你的模块申请到的主设备号是254,
* 运行"mknod abc c 254 0",就建立了我们的设备文件abc。
* 可以把它当成一个4096字节的内存块来测试一下,
* 比如"cat abc", "cp abc image", "cp image abc",
* 或写几个应用程序用它来进行通讯。

* 介绍一下两个需要注意的事,
* 一是printk()的显示只有在非图形模式的终端下才能看到,
* 二是加载过的模块最好在不用以后卸载掉。

* 如果对Linux环境的系统调用很陌生,建议先看APUE这本书。
*/

static int
asdf_open /* open回调 */
(
struct inode *inode,
struct file *filp
){
printk("^_^ : open %s\n ",\
current->comm);
/*
* 应用程序的运行环境由内核提供,内核的运行环境由硬件提供。
* 这里的current是一个指向当前进程的指针,
* 现在没必要了解current的细节。
* 在这里,当前进程正打开这个设备,
* 返回0表示打开成功,内核会给它一个文件描述符。
* 这里的comm是当前进程在Shell下的command字符串。
*/
return 0;
}

static int
asdf_release /* close回调 */
(
struct inode *inode,
struct file *filp
){
printk("^_^ : close\n ");
return 0;
}

static ssize_t
asdf_read /* read回调 */
(
struct file *filp,
char *buf,
size_t count,
loff_t *f_pos
){
loff_t pos;
pos = *f_pos; /* 文件的读写位置 */
if ((pos==4096) || (count>4096)) return 0; /* 判断是否已经到设备尾,或写的长度超过设备大小 */
pos += count;
if (pos > 4096) {
count -= (pos – 4096);
pos = 4096;
}
if (copy_to_user(buf, asdf_body+*f_pos, count)) return -EFAULT; /* 把数据写到应用程序空间 */
*f_pos = pos; /* 改变文件的读写位置 */
return count; /* 返回读到的字节数 */
}

static ssize_t
asdf_write /* write回调,和read一一对应 */
(
struct file *filp,
const char *buf,
size_t count,
loff_t *f_pos
){
loff_t pos;
pos = *f_pos;
if ((pos==4096) || (count>4096)) return 0;
pos += count;
if (pos > 4096) {
count -= (pos – 4096);
pos = 4096;
}
if (copy_from_user(asdf_body+*f_pos, buf, count)) return -EFAULT;
*f_pos = pos;
return count;
}

static loff_t
asdf_lseek /* lseek回调 */
(
struct file * file,
loff_t offset,
int orig
){
loff_t pos;
pos = file->f_pos;
switch (orig) {
case 0:
pos = offset;
break;
case 1:
pos += offset;
break;
case 2:
pos = 4096+offset;
break;
default:
return -EINVAL;
}
if ((pos>4096) || (pos<0)) {
printk("^_^ : lseek error %d\n",pos);
return -EINVAL;
}
return file->f_pos = pos;
}
———————————————

 

http://ithelp1979.spaces.live.com/blog/

2006年10月05日

cjk文件目录
org/apache/lucene/analysis/cjk

文件名: CJKAnalyzer.java
      CJKTokenizer.java
可以到google搜索一下,就可以找到这2个文件

索引的时候:
lucene自带的分词:
IndexWriter writer=new IndexWriter(indexDir,newStandardAnalyzer(),true);
用cjk分词:
IndexWriter writer=new IndexWriter(indexDir,newCJKAnalyzer(),true);

搜索的时候:
Searcher searcher = newIndexSearcher("D:\\Indexer");
Analyzer analyzer = newCJKAnalyzer();      //cjk分词
String[] fields = {"title","description","tag"};        
Query query = MultiFieldQueryParser.parse(q,fields, analyzer);
Hits hits = searcher.search(query);

Query query=QueryParser.parse(q,"title",newStandardAnalyzer()); //lucene自带

北斗搜索-最好用的搜索引擎
http://www.bydou.com
2006年10月02日
在eclipse中实现nutch运行
2006-07-20 10:56
快速部署nutch0.7.2

1. 把下载的nutch的内容解压到nutch-0.7, copy到eclipse的workspace下,  使用eclipse新建nutch工程, 工程名要和copy过来的nutch目录名一样, 即nutch-0.7, 这样就可以用eclipse自动分析功能, 把nutch-0.7下所有东西加入到eclipse下来

打开src下test下的nutch-site.xml文件加入如下:
<property>
  <name>plugin.folders</name>
  <value>D:\eclipse312\workspace\nutch-0.7\plugins</value>
  <description>Directories where nutch plugins are located.  Each
  element may be a relative or absolute path.  If absolute, it is used
  as is.  If relative, it is searched for on the classpath.</description>
</property>
其中D:\eclipse312\workspace\nutch-0.7\plugins根据你的情况定

2. 在d:/eclipse/workspace/nutch下创建一个urls.txt文件, 里面加入一行要search的网址, for example, http://www.xxx.com

3. 配置conf目录. 把nutch/conf目录添加到eclipse的class目录中(在libraries->Add classes folder), 这样nutch就可以找到conf下的配置文件了, 如果要用代理的话, 在nutch-default.xml文件中配置http.proxy.host

4. 配置plugin目录, 在nutch-default.xml文件中配置plugin.folders, nutch/plugins目录添加到eclipse的class目录

5. 在eclipse中的run中添加

org.apache.nutch.tools.CrawlTool urls.txt -dir crawl.test -depth 2 (抓取. 其中crawl.test指定的webdb和index目录)

org.apache.nutch.segment.SegmentReader -dump -dir crawl.test/segments/ (打印segments内容)

org.apache.nutch.db.WebDBReader crawl.test/db -dumplinks (打印webdb内容)

6. 运行时还要把RegexURLFilter.java考到src/java/org/apache/nutch/net下来, 再运行crawlTool

7. 进行crawling. waiting for crawling, 大概要一阵子, 这与你的网站上页面数有关, 你可以看到crawl.test目录下产生一堆文件和目录

8. 配置web search服务. 把nutch*.war考到tomcat的webapps下, 运行tomcat, 这时tomcat会自动解压nutch*.war到nutch*目录

9. 进入nutch*目录, 修改web-inf/classes下的nutch-default.xml文件, 找到searcher.dir项, 改为你的index目录, 例如crawl.test
<property>
    <name>searcher.dir</name>
    <value>d:/eclipse/workspace/nutch/crawl.test</value>
  </property>

8. reboot tomcat, search ok!

 

http://hi.baidu.com/ganyu21/blog/item/90fb2ddd9def79d98d102913.html