??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲AV午夜成人片,亚洲人妻av伦理,亚洲AV色香蕉一区二区http://www.tkk7.com/hua/category/12539.html即世界明天毁灭Q我也要在今天种下我的葡萄树?zh-cnFri, 21 Sep 2007 11:17:23 GMTFri, 21 Sep 2007 11:17:23 GMT60ANT 下蝲,ant的配?http://www.tkk7.com/hua/archive/2007/09/18/146061.html?/dc:creator>?/author>Tue, 18 Sep 2007 01:44:00 GMThttp://www.tkk7.com/hua/archive/2007/09/18/146061.htmlhttp://www.tkk7.com/hua/comments/146061.htmlhttp://www.tkk7.com/hua/archive/2007/09/18/146061.html#Feedback0http://www.tkk7.com/hua/comments/commentRss/146061.htmlhttp://www.tkk7.com/hua/services/trackbacks/146061.html下蝲http://www.apache.org/dist/ant/binaries下的apache-ant-1.6.1-bin.zip
接压安装?

ant的配法:
1。解压ant的包到本地目录?
2。在环境变量中设|ANT_HOMEQgؓ你的安装目录?
3。在环境变量中设|JAVA_HOMEQgؓ你的jdk安装目录?
4。把ANT_HOME/bin加到你系l的path目录中去?

SET ANT_HOME=D:\jakarta-ant-1.5.1 //注意是Ant的安装目录,不是bin子目?
SET PATH=%PATH%;%ANT_HOME%\bin;


在cmd模式下输?ant -version回RQ看到输明配|成功?



]]>
深入 JAVA对象的复制与比较http://www.tkk7.com/hua/archive/2007/01/10/92836.html?/dc:creator>?/author>Wed, 10 Jan 2007 02:46:00 GMThttp://www.tkk7.com/hua/archive/2007/01/10/92836.htmlhttp://www.tkk7.com/hua/comments/92836.htmlhttp://www.tkk7.com/hua/archive/2007/01/10/92836.html#Feedback0http://www.tkk7.com/hua/comments/commentRss/92836.htmlhttp://www.tkk7.com/hua/services/trackbacks/92836.html   
String str1 = "This is a string!"  //q里?"对象引用" 的复?
String str2 = new String(str1);  //q里?"对象实例" 的复?

复? 只复制复合对象本w?
深复? 除了复制复合对象本n, q复制了复合对象的引用的对象实例.

例如:

class Pupil{
    public Pupil(String sno, String name, int age){
        this.sno = new String(sno);
        this.name = new String(name);
        this.age = age;
    }

    public String getSno() {
        return sno;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    private String sno;
    private String name;
    private int age;
}

public class CopyDemo {
    public static Pupil[] shallowCopy(Pupil[] aClass) {
        Pupil[] newClass = new Pupil[aClass.length];

        //此时newClass 与aClass 指向同一块内?
        for(int i=0; i<aClass.length; i++)
            newClass[i] = aClass[i];
        return newClass;
    }
    
    public static Pupil[] deepCopy(Pupil[] aClass) {
        Pupil[] newClass = new Pupil[aClass.length];

        //此时newClass 与aClass 的相应sno , name 指向同一块内?
        for(int i=0; i<aClass.length; i++) {
            String sno = aClass[i].getSno();
            String name = aClass[i].getName();
            int age = aClass[i].getAge();
            newClass[i] = new Pupil(sno, name, age);
        }

        return newClass;
    }

    public static Pupil[] deeperCopy(Pupil[] aClass) {
        Pupil[] newClass = new Pupil[aClass.length];

        //完全的复?
        for(int i=0; i<aClass.length; i++) {
            String sno = new String(aClass[i].getSno());
            String name = new String(aClass[i].getName());
            int age = aClass[i].getAge();
            newClass[i] = new Pupil(sno, name, age);
        }

        return newClass;
    }
}

2.clone()的?/p>

* Object.clone()
* Cloneable 接口
* CloneNotSupportedException

a. 使用Object.clone q行复制
两个必须条g:
1.一定要重定义后的clone() Ҏ定义为公有方?在Object cM, 它是受保护的成员,    不能直接使用)
2.该后代类声明实现接口 Cloneable 接口(当类实现该接? 其Q何子cM会承该接口), 该接口实际上没有M
  内容, 只是一个标? 标志实现该接口的cL供clone() Ҏ.(q是接口的一U非典型用法)

public class Fraction implements Cloneable {
    public Object clone() {
        try{
            return super.clone();  //call protected method
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
    //other methods ...
}


b.重写Object.clone()
例如对 ?private char[] cb; character buffer q行复制
 
// add in class Cirbuf
        public Object clone() {
        try{
            Cirbuf copy = (Cirbuf)super.clone();
            copy.cb = (char[])cb.clone();
            return copy;
        }catch (CloneNotSupportedException e){
            throw new InternalError(e.toString());
        }
    }

c.复制数组
  数组是在Ҏ调用重以引用的Ş式传递的对象. 下述情况下非帔R合引用来传递数l?
  *正在接收的方法不修改数组
  *正在调用的方法不必关心是否修Ҏl?br />  *正在调用的方法想要得到数l中的修改结?
  否则, 应该在Ҏ调用中传递数l对象的副本. 只需调用 arrObj.clone() Ҏ卛_完成数组arrObj 的复制操? 随后该数组副本强制转换为其正确cd:
      (type[])arrObj.clone();
   System.arraycopy Ҏ提供一U用于在数组间复制多个元素的有效方式.
        System.arraycopy(source, i, target, j, len)

3.对象实例的比?/p>

例如:

    Pupil p1 = new Pupil("99184001", "zhang3", 18);
    Pupil p2 = new Pupil("99184001", "zhang3", 18);

a. "=="
   if(p1 == p2)...
  此次试的是对象引用, 其结果肯定是false, 只要两个对象引用不是互ؓ别名׃会相{?
b. 比较?false

   if(p1.getSno() == p2.getSno() && p1.getName() == p2.getName()
     && p1.getAge() == p2.getAge()) ...;

c. 深比较 ?true[/code]  
  if(p1.getSno().equals(p2.getSno()) && p1.getName().equals(p2.getName())
     && p1.getAge() == p2.getAge()) ...;[/code]
    JAVA API 的跟cObject 也提供了equals() Ҏ, 但它只是比较两个对象引用, 而非比较两个对象实例.
    不管怎样, 如果需要比较Pupil cȝ对象(例如要将它们攑օ对象容器), 应该为Pupil c重定义equals() Ҏ:
   
    public boolean equals(Object otherobj) {
        //查otherobj 是否为空
        if(otherobj == null) return false;

        //查otherobj 是否是当前对象
        if(otherobj == this) return true;

        //查otherobj 是否h正确的类? x查是否可与当前对象比?
        if(!(otherobj instanceof Pupil)) return false;

        //otherobj 转换为Pupil cȝ对象引用
        Pupil tmpObj = (Pupil)otherobj;
        //关于学生是否相等的逻辑?
        if(sno.equals(tmpObj.sno) && name.equals(tmpObj.name)
             && age == tmpObj.age) return true;
        
        return false;
    }

   JAVA API 所提供的每个类几乎都提供了采用深比较策略的equals() Ҏ, 例如String cequals() Ҏ. 一般来? 用户自己定义的类也应当提供合适的equals() Ҏ, 特别是当E序要将其对象放入JAVA API 所提供的对象容器类的时? 
   按照U定, McL提供的equals() Ҏ所实现的相{比较应该是{h关系, x反? 对称性和传递? 另外一个类重定义了equals() Ҏ, 也应该重定义相应hashCode() Ҏ, 否则这个类的对象放入映对象容器时也会发生以外.



]]>
Java源码分析Q深入探讨Iterator模式 http://www.tkk7.com/hua/archive/2006/12/30/90946.html?/dc:creator>?/author>Sat, 30 Dec 2006 01:43:00 GMThttp://www.tkk7.com/hua/archive/2006/12/30/90946.htmlhttp://www.tkk7.com/hua/comments/90946.htmlhttp://www.tkk7.com/hua/archive/2006/12/30/90946.html#Feedback0http://www.tkk7.com/hua/comments/commentRss/90946.htmlhttp://www.tkk7.com/hua/services/trackbacks/90946.html
  下面我们先简单讨Z个根接口CollectionQ然后分析一个抽象类AbstractList和它的对应Iterator接口Qƈ仔细研究q代子模式的实现原理?br />
  本文讨论的源代码版本是JDK 1.4.2Q因为JDK 1.5在java.util中用了很多泛型代码Qؓ了简化问题,所以我们还是讨?.4版本的代码?br />
  集合cȝҎ口Collection

  Collection接口是所有集合类的根cd。它的一个主要的接口Ҏ是:

boolean add(Object c)

  add()Ҏ添加一个新元素。注意这个方法会q回一个booleanQ但是返回g是表C添加成功与否。仔l阅读doc可以看到QCollection规定Q如果一个集合拒l添加这个元素,无论M原因Q都必须抛出异常。这个返回DC的意义是add()Ҏ执行后,集合的内Ҏ否改变了Q就是元素有无数量,位置{变化)Q这是由具体cd现的。即Q如果方法出错,M抛出异常Q返回g仅表CҎ执行后这个Collection的内Ҏ无变化?br />
  cM的还有:

boolean addAll(Collection c);
boolean remove(Object o);
boolean removeAll(Collection c);
boolean remainAll(Collection c);

  Object[] toArray()Ҏ很简单,把集合{换成数组q回。Object[] toArray(Object[] a)Ҏ有点复杂了Q首先,q回的Object[]仍然是把集合的所有元素变成的数组Q但是类型和参数a的类型是相同的,比如执行Q?br />
String[] o = (String[])c.toArray(new String[0]);

  得到的o实际cd是String[]?br />
  其次Q如果参数a的大装不下集合的所有元素,q回的将是一个新的数l。如果参数a的大能装下集合的所有元素,则返回的q是aQ但a的内容用集合的元素来填充。尤其要注意的是Q如果a的大比集合元素的个数还多,a后面的部分全部被|ؓnull?br />
  最后一个最重要的方法是iterator()Q返回一个IteratorQP代子Q,用于遍历集合的所有元素?br />
  用Iterator模式实现遍历集合
 
  Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合cM抽象出来Q从而避免向客户端暴露集合的内部l构?br />
  例如Q如果没有用IteratorQ遍历一个数l的Ҏ是用烦引:

for(int i=0; i<array.size(); i++) { ... get(i) ... }

  而访问一个链表(LinkedListQ又必须使用while循环Q?br />
while((e=e.next())!=null) { ... e.data() ... }

  以上两种Ҏ客户端都必须事先知道集合的内部结构,讉K代码和集合本w是紧耦合Q无法将讉K逻辑从集合类和客L代码中分d来,每一U集合对应一U遍历方法,客户端代码无法复用?br />
  更恐怖的是,如果以后需要把ArrayList更换为LinkedListQ则原来的客L代码必须全部重写?br />
  决以上问题,Iterator模式L用同一U逻辑来遍历集合:

for(Iterator it = c.iterater(); it.hasNext(); ) { ... }

  奥秘在于客户端自w不l护遍历集合?指针"Q所有的内部状态(如当前元素位|,是否有下一个元素)都由Iterator来维护,而这个Iterator由集合类通过工厂Ҏ生成Q因此,它知道如何遍历整个集合?br />
  客户端从不直接和集合cL交道Q它L控制IteratorQ向它发?向前"Q?向后"Q?取当前元?的命令,可以间接遍历整个集合?br />
  首先看看java.util.Iterator接口的定义:

public interface Iterator {
 boolean hasNext();
 Object next();
 void remove();
}

  依赖前两个方法就能完成遍历,典型的代码如下:

for(Iterator it = c.iterator(); it.hasNext(); ) {
 Object o = it.next();
 // 对o的操?..
}

  在JDK1.5中,q对上面的代码在语法上作了简化:

// Type是具体的cdQ如String?br />for(Type t : c) {
// 对t的操?..
}

  每一U集合类q回的Iterator具体cd可能不同QArray可能q回ArrayIteratorQSet可能q回SetIteratorQTree可能q回TreeIteratorQ但是它们都实现了Iterator接口Q因此,客户端不兛_到底是哪UIteratorQ它只需要获得这个Iterator接口卛_Q这是面向对象的威力?br />
 Iterator源码剖析

  让我们来看看AbstracyList如何创徏Iterator。首先AbstractList定义了一个内部类Qinner classQ:

private class Itr implements Iterator {
...
}

  而iterator()Ҏ的定义是Q?br />
public Iterator iterator() {
 return new Itr();
}

  因此客户端不知道它通过Iterator it = a.iterator();所获得的Iterator的真正类型?br />
  现在我们兛_的是q个x为private的ItrcL如何实现遍历AbstractList的:

private class Itr implements Iterator {
 int cursor = 0;
 int lastRet = -1;
 int expectedModCount = modCount;
}

  ItrcM?个int变量Q还有一个隐含的AbstractList的引用)来实现遍历,cursor是下一ơnext()调用时元素的位置Q第一ơ调用next()返回烦引ؓ0的元素。lastRet记录上一ơ游标所在位|,因此它L比cursor??br />
  变量cursor和集合的元素个数军_hasNext()Q?br />
public boolean hasNext() {
 return cursor != size();
}

  Ҏnext()q回的是索引为cursor的元素,然后修改cursor和lastRet的|

public Object next() {
 checkForComodification();
 try {
  Object next = get(cursor);
  lastRet = cursor++;
  return next;
 } catch(IndexOutOfBoundsException e) {
  checkForComodification();
  throw new NoSuchElementException();
 }
}

  expectedModCount表示期待的modCount|用来判断在遍历过E中集合是否被修改过。AbstractList包含一个modCount变量Q它的初始值是0Q当集合每被修改一ơ时Q调用addQremove{方法)QmodCount?。因此,modCount如果不变Q表C集合内Ҏ被修攏V?br />
  Itr初始化时用expectedModCount记录集合的modCount变量Q此后在必要的地方它会检modCount的|

final void checkForComodification() {
 if (modCount != expectedModCount)
  throw new ConcurrentModificationException();
}

  如果modCount与一开始记录在expectedModeCount中的g{,说明集合内容被修改过Q此时会抛出ConcurrentModificationException?br />
  q个ConcurrentModificationException是RuntimeExceptionQ不要在客户端捕获它。如果发生此异常Q说明程序代码的~写有问题,应该仔细查代码而不是在catch中忽略它?br />
  但是调用Iterator自n的remove()Ҏ删除当前元素是完全没有问题的Q因为在q个Ҏ中会自动同步expectedModCount和modCount的|

public void remove() {
...
AbstractList.this.remove(lastRet);
...
// 在调用了集合的remove()Ҏ之后重新讄了expectedModCountQ?br />expectedModCount = modCount;
...
}

  要确保遍历过E顺利完成,必须保证遍历q程中不更改集合的内容(Iterator的remove()Ҏ除外Q,因此Q确保遍历可靠的原则是只在一个线E中使用q个集合Q或者在多线E中寚w历代码进行同步?br />
  最后给个完整的CZQ?br />
Collection c = new ArrayList();
c.add("abc");
c.add("xyz");
for(Iterator it = c.iterator(); it.hasNext(); ) {
 String s = (String)it.next();
 System.out.println(s);
}

  如果你把W一行代码的ArrayList换成LinkedList或VectorQ剩下的代码不用改动一行就能编译,而且功能不变Q这是针对抽象~程的原则:对具体类的依赖性最?img src ="http://www.tkk7.com/hua/aggbug/90946.html" width = "1" height = "1" />

]]>
JS的正则表辑ּhttp://www.tkk7.com/hua/archive/2006/12/22/89504.html?/dc:creator>?/author>Fri, 22 Dec 2006 05:51:00 GMThttp://www.tkk7.com/hua/archive/2006/12/22/89504.htmlhttp://www.tkk7.com/hua/comments/89504.htmlhttp://www.tkk7.com/hua/archive/2006/12/22/89504.html#Feedback0http://www.tkk7.com/hua/comments/commentRss/89504.htmlhttp://www.tkk7.com/hua/services/trackbacks/89504.html阅读全文

]]>
深入Java中文问题及最优解x?/title><link>http://www.tkk7.com/hua/archive/2006/09/26/72057.html</link><dc:creator>?/dc:creator><author>?/author><pubDate>Tue, 26 Sep 2006 08:54:00 GMT</pubDate><guid>http://www.tkk7.com/hua/archive/2006/09/26/72057.html</guid><wfw:comment>http://www.tkk7.com/hua/comments/72057.html</wfw:comment><comments>http://www.tkk7.com/hua/archive/2006/09/26/72057.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/hua/comments/commentRss/72057.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/hua/services/trackbacks/72057.html</trackback:ping><description><![CDATA[ <font style="BACKGROUND-COLOR: #ffffff" color="#000000">深入Java中文问题及最优解x?/font> <div class="t15p335" id="msgcns!AADDE4734A6787F!116"> <div> <font style="BACKGROUND-COLOR: #ffffff" color="#000000"> AbstractQ本文深入分析了JavaE序设计中Java~译器对java源文件和JVM对classcL件的~码/解码q程Q通过此过E的解析透视ZJava~程中中文问题生的Ҏ原因Q最后给Z的最优化的解决Java中文问题的方法。?</font> <p> <font style="BACKGROUND-COLOR: #ffffff"> <font color="#000000">  <strong>1、中文问题的来源 </strong></font> </font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    计算机最初的操作pȝ支持的编码是单字节的字符~码Q于是,在计机中一切处理程序最初都是以单字节编码的英文为准q行处理。随着计算机的发展Qؓ了适应世界其它民族的语aQ当然包括我们的汉字Q,Z提出了UNICODE~码Q它采用双字节编码,兼容英文字符和其它民族的双字节字W编码,所以,目前Q大多数国际***的Y件内部均采用UNICODE~码Q在软gq行Ӟ它获得本地支持系l(多数旉是操作系l)默认支持的编码格式,然后再将软g内部的UNICODE转化为本地系l默认支持的格式昄出来。Java的JDK和JVMx如此Q我q里说的JDK是指国际版的JDKQ我们大多数E序员用的是国际化的JDK版本Q以下所有的JDK均指国际化的JDK版本。我们的汉字是双字节~码语言Qؓ了能让计机处理中文Q我们自己制定的gb2312、GBK、GBK2K{标准以适应计算机处理的需求。所以,大部分的操作pȝZ适应我们处理中文的需求,均定制有中文操作pȝQ它们采用的是GBK,GB2312~码格式以正显C我们的汉字。如Q中文Win2K默认采用的是GBK~码昄Q在中文WIN2k中保存文件时默认采用的保存文件的~码格式也是GBK的,卻I所有在中文WIN2K中保存的文g它的内部~码默认均采用GBK~码Q注意:GBK是在GB2312基础上扩充来的?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    ׃Java语言内部采用UNICODE~码Q所以在JAVAE序q行Ӟ存在着一个从UNICODE~码和对应的操作pȝ及浏览器支持的编码格式{换输入、输出的问题Q这个{换过E有着一pd的步骤,如果其中M一步出错,则显C出来的汉字׃出是qQ这是我们常见的JAVA中文问题?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    同时QJava是一个跨q_的编E语aQ也x们编写的E序不仅能在中文windows上运行,也能在中文Linux{系l上q行Q同时也要求能在英文{系l上q行Q我们经常看到有人把在中文win2k上编写的JAVAE序Q移植到英文Linux上运行)。这U移植操作也会带来中文问题?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    q有Q有Z用英文的操作pȝ和英文的IE{浏览器Q来q行带中文字W的E序和浏览中文网,它们本n׃支持中文Q也会带来中文问题?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    几乎所有的览器默认在传递参数时都是以UTF-8~码格式来传递,而不是按中文~码传递,所以,传递中文参数时也会有问题,从而带来ؕ码现象?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    MQ以上几个方面是JAVA中的中文问题的主要来源,我们把以上原因造成的程序不能正运行而生的问题UCQJAVA中文问题?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff"> <font color="#000000"> <strong> 2、JAVA~码转换的详l过E?</strong></font> </font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    我们常见的JAVAE序包括以下cdQ?br />     *直接在console上运行的c?包括可视化界面的c?<br />     *JSP代码c(注:JSP是Servletscȝ变型Q?br />     *Serveletsc?br />     *EJBc?br />     *其它不可以直接运行的支持c?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    q些cL件中Q都有可能含有中文字W串Qƈ且我们常用前三类JAVAE序和用L接交互,用于输出和输入字W,如:我们在JSP和Servlet中得到客L送来的字W,q些字符也包括中文字W。无些JAVAcȝ作用如何Q这些JAVAE序的生命周期都是这LQ?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    *~程人员在一定的操作pȝ上选择一个合适的~辑软g来实现源E序代码q以.java扩展名保存在操作pȝ中,例如我们在中文win2k中用C本编辑一个java源程序;<br />     *~程人员用JDK中的javac.exe来编译这些源代码QŞ?classc?JSP文g是由容器调用JDK来编译的)Q?br />     *直接q行q些cL这些类布v到WEB容器中去q行Qƈ输出l果?br />    那么Q在q些q程中,JDK和JVM是如何将q些文g如何~码和解码ƈq行的呢Q?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">q里Q我们以中文win2k操作pȝZ说明JAVAcL如何来编码和被解码的?</font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000"> </font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    <strong>W一步,</strong>我们在中文win2k中用~辑软g如记事本~写一个Java源程序文?包括以上五类JAVAE序)Q程序文件在保存旉认采用了操作pȝ默认支持GBK~码格式(操作pȝ默认支持的格式ؓfile.encoding格式)形成了一?java文gQ也卻IjavaE序在被~译前,我们的JAVA源程序文件是采用操作pȝ默认支持的file.encoding~码格式保存的,java源程序中含有中文信息字符和英文程序代码;要查看系l的file.encoding参数Q可以用以下代码Q?br />  public class ShowSystemDefaultEncoding {<br />  public static void main(String[] args) {<br />  String encoding = System.getProperty("file.encoding");<br />  System.out.println(encoding);<br />  }}</font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">   <strong> W二步,</strong>我们用JDK的javac.exe文g~译我们的Java源程序,׃JDK是国际版的,在编译的时候,如果我们没有?encoding参数指定我们的JAVA源程序的~码格式Q则javac.exe首先获得我们操作pȝ默认采用的编码格式,也即在编译javaE序Ӟ若我们不指定源程序文件的~码格式QJDK首先获得操作pȝ的file.encoding参数(它保存的是操作pȝ默认的编码格式,如WIN2kQ它的gؓGBK)Q然后JDK把我们的java源程序从file.encoding~码格式转化为JAVA内部默认的UNICODE格式攑օ内存中。然后,javac把{换后的unicode格式的文件进行编译成.classcLӞ此时.class文g是UNICODE~码的,它暂攑֜内存中,紧接着QJDK此以UNICODE~码的编译后的class文g保存到我们的操作pȝ中Ş成我们见到的.class文g。对我们来说Q我们最l获得的.class文g是内容以UNICODE~码格式保存的类文gQ它内部包含我们源程序中的中文字W串Q只不过此时它己l由file.encoding格式转化为UNICODE格式了?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    q一步中Q对于JSP源程序文件是不同的,对于JSPQ这个过E是q样的:即WEB容器调用JSP~译器,JSP~译器先查看JSP文g中是否设|有文g~码格式Q如果JSP文g中没有设|JSP文g的编码格式,则JSP~译器调用JDK先把JSP文g用JVM默认的字W编码格?也即WEB容器所在的操作pȝ的默认的file.encoding)转化Z时的Servletc,然后再把它编译成UNICODE格式的classc,q保存在临时文g夹中。如Q在中文win2k上,WEB容器把JSP文g从GBK~码格式转化为UNICODE格式Q然后编译成临时保存的Servletc,以响应用Lh?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff"> <font color="#000000">    <strong>W三步,q行W二步编译出来的c,分ؓ三种情况Q?/strong></font> </font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff"> <font color="#000000">    A?直接在console上运行的c?br />    B?EJBcd不可以直接运行的支持c?如JavaBeanc?<br />    C?JSP代码和Servletc?br />    D?JAVAE序和数据库之间<br />    下面我们分这四种情况来看?br />   <strong> A、直接在console上运行的c?/strong></font> </font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    q种情况Q运行该c首先需要JVM支持Q即操作pȝ中必d装有JRE。运行过E是q样的:首先java启动JVMQ此时JVMd操作pȝ中保存的class文gq把内容d内存中,此时内存中ؓUNICODE格式的classc,然后JVMq行它,如果此时此类需要接收用戯入,则类会默认用file.encoding~码格式对用戯入的串进行编码ƈ转化为unicode保存入内存(用户可以讄输入的~码格式Q。程序运行后Q生的字符ԌUNICODE~码的)再回交给JVMQ最后JRE把此字符串再转化为file.encoding格式(用户可以讄输出的~码格式)传递给操作pȝ昄接口q输出到界面上?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    对于q种直接在console上运行的c,它的转化q程可用?更加明确的表C出来:</font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">?</font> </p> <p align="center"> <font style="BACKGROUND-COLOR: #ffffff" color="#000000"> <img style="CURSOR: pointer" src="http://www.pconline.com.cn/pcedu/empolder/gj/java/0404/pic/0430java_1.gif" /> </font> </p> <p align="left"> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">以上每一步的转化都需要正的~码格式转化Q才能最l不出现q现象?br /><br />    </font> <font style="BACKGROUND-COLOR: #ffffff"> <font color="#000000"> <strong>B、EJBcd不可以直接运行的支持c?如JavaBeanc?<br /><br /></strong>    ׃EJBcd不可以直接运行的支持c,它们一般不与用L接交互输入和输出Q它们常怸其它的类q行交互输入和输出,所以它们在W二步被~译后,Ş成了内容是UNICODE~码的类保存在操作系l中了,以后只要它与其它的类之间的交互在参数传递过E中没有丢失Q则它就会正的q行?br />q种EJBcd不可以直接运行的支持c? 它的转化q程可用?更加明确的表C出来: </font> </font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000"> </font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">?</font> </p> <p align="center"> <font style="BACKGROUND-COLOR: #ffffff" color="#000000"> <img style="CURSOR: pointer" src="http://www.pconline.com.cn/pcedu/empolder/gj/java/0404/pic/0430java_2.gif" /> </font> </p> <p> <br /> <font style="BACKGROUND-COLOR: #ffffff"> <font color="#000000">   <strong> C、JSP代码和Servletc?/strong></font> </font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    l过W二步后QJSP文g也被转化为ServletscLӞ只不q它不像标准的Servlets一校存在于classes目录中,它存在于WEB容器的时目录中Q故q一步中我们也把它做为Servlets来看?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    对于ServletsQ客Lh它时QWEB容器调用它的JVM来运行ServletQ首先,JVM把Servlet的classcMpȝ中读出ƈ装入内存中,内存中是以UNICODE~码的Servletcȝ代码Q然后JVM在内存中q行该Servletc,如果Servlet在运行的q程中,需要接受从客户端传来的字符如:表单输入的值和URL中传入的|此时如果E序中没有设定接受参数时采用的编码格式,则WEB容器会默认采用ISO-8859-1~码格式来接受传入的值ƈ在JVM中{化ؓUNICODE格式的保存在WEB容器的内存中。Servletq行后生成输出,输出的字W串是UNICODE格式的,紧接着Q容器将Servletq行产生的UNICODE格式的串Q如html语法Q用戯出的串等Q直接发送到客户端浏览器上ƈ输出l用P如果此时指定了发送时输出的编码格式,则按指定的编码格式输出到览器上Q如果没有指定,则默认按ISO-8859-1~码发送到客户的浏览器上。这UJSP代码和Servletc,它的转化q程可用?更加明确地表C出来:</font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">?</font> </p> <p align="center"> <font style="BACKGROUND-COLOR: #ffffff" color="#000000"> <img style="CURSOR: pointer" src="http://www.pconline.com.cn/pcedu/empolder/gj/java/0404/pic/0430java_3.gif" /> </font> </p> <p align="left"> <font style="BACKGROUND-COLOR: #ffffff"> <font color="#000000"> <strong>D、JavaE序和数据库之间</strong> </font> </font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000"> </font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    对于几乎所有数据库的JDBC驱动E序Q默认的在JAVAE序和数据库之间传递数据都是以ISO-8859-1为默认编码格式的Q所以,我们的程序在向数据库内存储包含中文的数据ӞJDBC首先是把E序内部的UNICODE~码格式的数据{化ؓISO-8859-1的格式,然后传递到数据库中Q在数据库保存数据时Q它默认即以ISO-8859-1保存Q所以,q是Z么我们常常在数据库中d的中文数据是q?br />    对于JAVAE序和数据库之间的数据传递,我们可以用图4清晰地表C出?/font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">?</font> </p> <p align="center"> <font style="BACKGROUND-COLOR: #ffffff" color="#000000"> <img style="CURSOR: pointer" src="http://www.pconline.com.cn/pcedu/empolder/gj/java/0404/pic/0430java_4.gif" /> </font> </p> <p> <br /> <font style="BACKGROUND-COLOR: #ffffff"> <font color="#000000"> <strong>    3、分析常见的JAVA中文问题几个必须清楚的原?br /></strong> <br />    首先Q经q上面的详细分析Q我们可以清晰地看到QQ何JAVAE序的生命期中,其编码{换的关键q程是在于:最初编译成class文g的{码和最l向用户输出的{码过E?br />    其次Q我们必M解JAVA在编译时支持的、常用的~码格式有以下几U:<br />    *ISO-8859-1Q?-bit, ?859_1,ISO-8859-1,ISO_8859_1{编?br />    *Cp1252Q美国英语编码,同ANSI标准~码<br />    *UTF-8Q同unicode~码<br />    *GB2312Q同gb2312-80,gb2312-1980{编?br />    *GBK , 同MS936Q它是gb2312的扩?br />    及其它的~码Q如韩文、日文、繁体中文等。同Ӟ我们要注意这些编码间的兼容关体系如下Q?br />    unicode和UTF-8~码是一一对应的关pRGB2312可以认ؓ是GBK的子集,即GBK~码是在gb2312上扩展来的。同ӞGBK~码包含?0902个汉字,~码范围为:0x8140-0xfefeQ所有的字符可以一一对应到UNICODE2.0中来?/font> </font> </p> <p> <font style="BACKGROUND-COLOR: #ffffff" color="#000000">    再次Q对于放在操作系l中?java源程序文Ӟ在编译时Q我们可以指定它内容的编码格式,具体来说?encoding来指定。注意:如果源程序中含有中文字符Q而你?encoding指定为其它的~码字符Q显然是要出错的。用-encoding指定源文件的~码方式为GBK或gb2312Q无论我们在什么系l上~译含有中文字符的JAVA源程序都不会有问题,它都会正地中文{化ؓUNICODE存储在class文g中?br />    <br />    然后Q我们必L楚,几乎所有的WEB容器在其内部默认的字W编码格式都是以ISO-8859-1为默认值的Q同Ӟ几乎所有的览器在传递参数时都是默认以UTF-8的方式来传递参数的。所以,虽然我们的Java源文件在出入口的地方指定了正的~码方式Q但其在容器内部q行时还是以ISO-8859-1来处理的?/font> </p> </div> </div> <img src ="http://www.tkk7.com/hua/aggbug/72057.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/hua/" target="_blank">?/a> 2006-09-26 16:54 <a href="http://www.tkk7.com/hua/archive/2006/09/26/72057.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>javamailȝl验http://www.tkk7.com/hua/archive/2006/08/31/66915.html?/dc:creator>?/author>Thu, 31 Aug 2006 09:39:00 GMThttp://www.tkk7.com/hua/archive/2006/08/31/66915.htmlhttp://www.tkk7.com/hua/comments/66915.htmlhttp://www.tkk7.com/hua/archive/2006/08/31/66915.html#Feedback0http://www.tkk7.com/hua/comments/commentRss/66915.htmlhttp://www.tkk7.com/hua/services/trackbacks/66915.html javamailȝl验Q一Q?/a> 环境配置。ؓ了运行javamail。我们需要在classpath里导入两个包Qmail.jar和activation.jarQ这是在UDOS里或者其它简单工具用时才需要这个classpath。如果用像eclipesq样的工具就不需要配|。因为myeclipes已经帮你做好了?br />Z要发送邮件和接收邮gQ我们必要遵守smtp和pop3协议Q不q还有其它协议也可执?如IMAP)。如果把本机当作服务器来发送邮件请?a >http://jakrata.apache.org|站里下载james邮g服务器,然后解压在本Z。运行james/bin里的run.bat可以启动了服务器?br />q行后在DOS里登录邮件服务器。具体命令如下:
pȝ理员:root
密码Qroot
telnet localhost 4555
然后可以增加邮q户名了。命令如下:
adduser 用户名 密?br />例:adduser test test
q样徏立了q样一个邮test@localhost 密码为:test 
如果惌更多功能用help命o
注意Q如果在本机装了邮g服务器的话,只能在本机局域网里申请邮,发送和接收。不能发送到外部的邮里厅R如果用外部的邮件服务器像比?63?26的服务器{就可以随心所Ʋ的发邮件了。哈哈是不是很爽呢?
先看看用james邮g服务器在本机上发邮g吧。先单看一个例子?br />import javax.mail.*;
import java.util.*;
import javax.mail.internet.*;
public class MyFirstMail 
{
    protected Session mailSession;
    public MyFirstMail()throws Exception
    {
        init();
    }
    public static void main(String[] args) 
    {
        try
        {
            new MyFirstMail().sendMail();
            System.out.print("邮g已发");
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
//初始化服务器环境
    public void init()throws Exception
    {
        Properties props=new Properties();
        props.put("mail.transport.protocol","smtp");
        props.put("mail.smtp.host","localhost");
        props.put("mail.smtp.port","25");
        mailSession=Session.getDefaultInstance(props, null);;
    }
    public void sendMail()throws Exception
    {
        try
        {
            
//从哪里发的邮件           ?br />msg.setFrom(new InternetAddress("test@localhost"));
    //发送到目标邮g        msg.setRecipients(Message.RecipientType.TO,InternetAddress.parse("wang@localhost"));
    //抄送的接收者        msg.setRecipients(Message.RecipientType.CC,InternetAddress.parse("wang@localhost"));
//暗送的接收?br />msg.setRecipients(Message.RecipientType.BCC,InternetAddress.parse("wang@localhost"));
//讄发送时?br />msg.setSentDate(new java.util.Date());
//讄邮g标题
msg.setSubject("a test mail");
//讄邮g内容
msg.setText("this is the email content");
//指定协议发送消息的对像
Transport transport=mailSession.getTransport("smtp");
//发送消?br />Transport.send(msg);
}
catch(Exception e)
{
throw e;
}
}
发送完后想要看邮gp到james->apps->james->var->mail->inboxes可以看见每个邮里的邮件数了。由于发q来的是字节,邮g包括一个邮件属性和消息Q所以每一邮件是׃个文件组成的?br />            
也许没有学过的javamail的h看上M一头雾水。不要紧Q现在一一详解。先说初始化的内容的吧!
1、    mail.transport.protocol=smtp q里主要说明的是邮g传输协议?br />2、    mail.smtp.host=localhost 发送邮件的L如果用外部邮件服务器的话Q可以这样写
mail.smtp.host=smtp.163.comq样׃163.为服务器了?br />3、mail.smtp.prot=25    smtp端口可以省略Q缺省ؓ25

javax.mail.session
sessioncd义了与远E邮件系l通信的邮件会话。需要注意的是这个session不同servlet中的会话。Servlet中的会话需要共享一些信息,而mail里的session里没有这个功能,它只是用于存储与服务器徏立连接会话相关信息和逻辑。SessioncLjavamail api最高层入口c,所有其它类都必ȝ由session对象生效。Session对象它管理配|选项和用于与邮gpȝ交互的用认证信息息。它通过使用java.util.properties对象配置邮g会话的属性如邮g服务器,用户名,密码Q及整个应用E序中共享的其它信息?br />Sessionq不处现M授权操作Q它只是存储q些授权信息。Sessioncȝ构造器是私有的Q它不能被承,也不能用new语名创徏实例。但它提供了两个静态方法getInstance 和getDefaultInstance来获取session实例Q在创徏session实例旉要提供一些属性。具体实现如下:
    Properties props=new Properties()
    Props.put(“mail.transport.protocol?”smtp?
    Props.put(“mail.smtp.host?”localhost?;
  Props.put(“mail.smtp.prot??5?
//不加以认证也可以q样?br />//Session session=Session.getDefaultInstance(props,null)
//如果认证传入null那么它和不用认证调用方式一样?br /> Session session=Session.getDefaultInstance(props)
Javax.mail. Message
l过session配置后就可以q行发送消息Q务了。这由MessagecL完成。Message实现了Part接口Q它表示一个邮件消息,包含一pd的属性和一个消息内宏V消息属性包括了消息址址消息Q定义了消息内容的结构(包括内容cdQ,消息内容使用DataHandler对象包装实际数据。当邮g消息位于目录(folder)中时Q系l还使用了一个标志位集合来描q它的状态?br />Message是抽象类Q实际用时必须用一个子cM替以表示具体的邮件格式。比如说javamail api提供了MimeMessagec,该类扩展了MessageQ实CRFC822和MIME标准。有两个构造方法:
//一般用第一U?br />    Message msg=new MimeMessage(Session session)
Message msg=new MimeMessage(MimeMessage msg)
获得消息后,可以设|消息各个部份了。在讄之前因ؓ要涉及地址。所以讲一下地址c?br />javax.mail.Address
Addressc表C电子邮件类Q它是一个抽象类Q它的子cInternetAddress提供具体实现且通常可串行化。若创徏的地址只包含电子邮Ӟ只要传递电子邮件到构造器卛_?br />InternetAddress addr=new InternetAddress();
addr.setAddress(“wang@126.com?
或者是QInterntAddress addr=new InternetAddress(“wang@126.com?
另外QInternetAddressc还提供了地址解析Ҏ?br />Address[] addrs=InternetAddress.parse(“wang@163.com,f@126.com,zuo@126.com?;
地址之后可以发送消息了?br />//讄发送?br />Msg.setFrom(new InternetAddress(“test@126.com?);
//讄接收?q还h解析功能
Msg.setRecipients(Message.RecipientType.To,InternetAddress.parse(“zuolin0806@163.com?);
//抄送的接收?br />Msg.setRecipients(Message.RecipientType.CC,InternetAddress.parse(“zuolin0806@163.com?);
//暗送的接收?br />Msg.setRecipients(Message.RecipientType.CC,InternetAddress.parse(“zuolin0806@163.com?);
//讄消息主题
 msg.setSubject(“我的爱?
//讄内容的基本机Ӟ其参数Mimecd
 msg.setContent(“这是我的内容?”text/html;charset=gb2312?
其中的text/html表示消息内容采用的是HTML格式。如果消息格式是(text/plain)Q而且使用的是MimeMessage,那么setText()Ҏ讄邮g内容的参敎ͼMimecd默认为text/plainQ?br />//讄邮g内容
msg.setText();
//讄发送时?br />msg.setSentDate(new java.util.Date());
最后一步是是发送了
javax.mail.Transport
该类也是抽象c,它可通过静态方法和实便Ҏ发送消息。Transport断承servicecR所以它提供了通用ҎQ如命名传输Q连接服务器和监听传输事件等?br />//默认
Transport.send(msg);

最后看一下用外部邮件服务器的用方法。先看程序再讲解Q注意在使用外部邮g服务器时一定要有一个类来认证。到时在讌Ӏ?br />public class MySecondMail
{
protected Session session = null;
//邮g用户?br />    String mailUser = "zuolin0806";
    String host = "smtp.163.com";
    String pwd = "用户名的密码";
    public MySecondMail()
    {
        init();
    }

    public void init()
    {
        Properties props = new Properties();
        props.put("mail.transpost.protocol", "smtp");
        props.put("mail.smtp.host", "smtp.163.com");
        //必须要有一个类来认?br />props.put("mail.smtp.auth", "true");
props.put("mail.smpt.port", "25")
Email_Autherticatorbean auth =  new Email_Autherticatorbean(mailUser,pwd);
        //session认证
session = Session.getInstance(props,auth);
        //q个是跟t后台消息。打印在控制?br />session.setDebug(true);
   }
    public static void main(String[] args)
    {
        new MySecondMail().sendMails();
        System.out.println("send mail success!");
    }
    public void sendMails()
    {
        try
        {
            Message msg = new MimeMessage(session);
         msg.setFrom(new InternetAddress("zuolin0806@163.com"));
        msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("javaboy@126.com"));
       msg.setRecipients(Message.RecipientType.BCC, InternetAddress.parse("javaboy@126.com"));
      msg.setSentDate(new Date());
      msg.setSubject("this is my Threee mail");
      msg.setContent("this is my mail","text/html");
      msg.setText("我成功了。哈?);

     Transport transport = session.getTransport("smtp");
      与发送者的邮箱相连
transport.connect(host,mailUser,pwd);
      transport.send(msg);
        }
        catch (SendFailedException e)
        {
            e.printStackTrace();
        }
        catch (Exception ee)
        {
            ee.printStackTrace();
        }

    }
}

认证cdȝ承Authenticator  例子如下:
import javax.mail.*;
public class Email_Autherticatorbean extends Authenticator
{
    private String m_username = null;
    private String m_userpass = null;
    public void setUsername(String username)
    {
        m_username = username;
    }
    public void setUserpass(String userpass)
    {
        m_userpass = userpass;
    }
    public Email_Autherticatorbean(String username, String userpass)
    {
        super();
        setUsername(username);
        setUserpass(userpass);
    }
    public PasswordAuthentication getPasswordAuthentication()
    {
        return new PasswordAuthentication(m_username,m_userpass);
    }
}
l过成功发送邮件后是不是有Ҏ感呢!但还有很多疑问比如怎么读邮件呢Q看了下面章节你׃知道?br />

]]>
正则表达式regular expression详述 http://www.tkk7.com/hua/archive/2006/08/30/66738.html?/dc:creator>?/author>Wed, 30 Aug 2006 15:16:00 GMThttp://www.tkk7.com/hua/archive/2006/08/30/66738.htmlhttp://www.tkk7.com/hua/comments/66738.htmlhttp://www.tkk7.com/hua/archive/2006/08/30/66738.html#Feedback0http://www.tkk7.com/hua/comments/commentRss/66738.htmlhttp://www.tkk7.com/hua/services/trackbacks/66738.html正则表达式是regular expressionQ看来英文比中文要好理解多了Q就是检查表辑ּW?
不符合规定!Q正则表辑ּ有一个功能十分强大而又十分复杂的对象RegExpQ在Javascript1.2 版本?
上提供?
下面我们看看有关正则表达式的介绍Q?
正则表达式对象用来规范一个规范的表达?也就是表辑ּW不W合特定的要求,比如是不是Email
地址格式{?Q它h用来查给出的字符串是否符合规则的属性和Ҏ?
除此之外Q你用RegExp构造器建立的个别正则表辑ּ对象的属性,已l预先定义好了正则表辑ּ
对象的静态属性,你可以随时用它们?
核心对象Q?
在Javascript 1.2, NES 3.0以上版本提供?
在Javascript 1.3以后版本增加了toSourceҎ?
建立ҎQ?
文字格式或RegExp构造器函数?
文字建立格式使用以下格式Q?
/pattern/flags?模式/标记

构造器函数Ҏ使用Ҏ如下Q?
new RegExp("pattern"[, "flags"])即new RegExp("模式"[,"标记"])

参数Q?
pattern(模式)
表示正则表达式的文本

flags(标记)
如果指定此项Qflags可以是下面g一Q?
g: global match(全定匚w)
i: ignore case(忽略大小?
gi: both global match and ignore case(匚w所有可能的|也忽略大写)


 

注意Q文本格式中的参C要用引h讎ͼ而构造器函数的参数则要用引h记。所以下面的
表达式徏立同L正则表达式:
/ab+c/i
  new RegExp("ab+c", "i")

描述Q?
当用构造函数的时候,必须使用正常的字W串避开规则(在字W串中加入前导字W?)是必ȝ?
例如Q下面的两条语句是等LQ?
re = new RegExp("\w+")
re = /w+/

下面的提供了在正则表辑ּ中能够用的完整对特D字W的一个完整的列表和描q?

?.3Q正则表辑ּ中的Ҏ字符Q?

字符
意义Q对于字W,通常表示按字面意义,指出接着的字WؓҎ字符Q不作解释?
例如Q?b/匚w字符'b',通过在b 前面加一个反斜杠Q也是/b/Q则该字W变成特D字W,表示
匚w一个单词的分界Uѝ?
或者: 
对于几个字符Q通常说明是特D的Q指出紧接着的字W不是特D的Q而应该按字面解释?
例如Q?是一个特D字W,匚wL个字W?包括0个字W?Q例如:/a*/意味匚w0个或多个a?
Z匚w字面上的*Q在a前面加一个反斜杠Q例如:/a*/匚w'a*'?

字符^
意义Q表C匹配的字符必须在最前边?
例如Q?^A/不匹?an A,"中的'A'Q但匚w"An A."中最前面?A'?

字符$
意义Q与^cMQ匹配最末的字符?
例如Q?t$/不匹?eater"中的't'Q但匚w"eat"中的't'?

字符*
意义Q匹?前面的字W?ơ或nơ?
例如:/bo*/匚w"A ghost booooed"中的'boooo'?A bird warbled"中的'b'Q但不匹?A goat g
runted"中的M字符?

字符+
意义Q匹?号前面的字符1ơ或nơ。等价于?
例如Q?a+/匚w"candy"中的'a'?caaaaaaandy."中的所?a'?

字符?
意义Q匹?前面的字W?ơ或1ơ?
例如Q?e?le?/匚w"angel"中的'el'?angle."中的'le'?

字符.
意义Q?数?匚w除换行符外的所有单个的字符?
例如Q?.n/匚w"nay, an apple is on the tree"中的'an'?on'Q但不匹?nay'?


字符(x)
意义Q匹?x'q记录匹配的倹{?
例如Q?(foo)/匚w和记?foo bar."中的'foo'。匹配子串能被结果数l中的素[1], ..., [n] q?
回,或被RegExp对象的属?1, ..., $9q回?

字符x|y
意义Q匹?x'或?y'?
例如Q?green|red/匚w"green apple"中的'green'?red apple."中的'red'?

字符
意义Q这里的n是一个正整数。匹配前面的n个字W?
例如Q?a/不匹?candy,"中的'a'Q但匚w"caandy," 中的所?a'?caaandy."中前面的两个
'a'?

字符
意义Q这里的n是一个正整数。匹配至n个前面的字符?
例如Q?a不匹?candy"中的'a'Q但匚w"caandy"中的所?a'?caaaaaaandy."中的所?a'

字符
意义Q这里的n和m都是正整数。匹配至n个最多m个前面的字符?
例如Q?a/不匹?cndy"中的M字符Q但匚w "candy,"中的'a'Q?caandy," 中的前面两个
'a'?caaaaaaandy"中前面的三个'a'Q注意:即"caaaaaaandy" 中有很多?a'Q但只匹配前面的?
?a'?aaa"?

字符[xyz]
意义Q一字符列表Q匹配列Z的Q一字符。你可以通过q字W?指出一个字W范围?
例如Q[abcd]跟[a-c]一栗它们匹?brisket"中的'b'?ache"中的'c'?

字符[^xyz]
意义Q一字符补集Q也是_它匹配除了列出的字符外的所有东ѝ?你可以用连字符-指出一
字符范围?
例如Q[^abc]和[^a-c]{hQ它们最早匹?brisket"中的'r'?chop."中的'h'?

字符[b]
意义Q匹配一个空?不要与bh)

字符b
意义Q匹配一个单词的分界U,比如一个空?不要与[b]h)
例如Q?bnw/匚w"noonday"中的'no'Q?wyb/匚w"possibly yesterday."中的'ly'?

字符B
意义Q匹配一个单词的非分界线
例如Q?wBn/匚w"noonday"中的'on'Q?yBw/匚w"possibly yesterday."中的'ye'?

字符cX
意义Q这里的X是一个控制字W。匹配一个字W串的控制字W?
例如Q?cM/匚w一个字W串中的control-M?

字符d
意义Q匹配一个数字,{h于[0-9]?
例如Q?d/?[0-9]/匚w"B2 is the suite number."中的'2'?

字符D
意义Q匹配Q何的非数字,{h于[^0-9]?
例如Q?D/?[^0-9]/匚w"B2 is the suite number."中的'B'?

字符f
意义Q匹配一个表单符

字符n
意义Q匹配一个换行符

字符r
意义Q匹配一个回车符

字符s
意义Q匹配一个单个whiteI格W,包括I格QtabQform feedQ换行符Q等价于[ fnrtv]?
例如Q?sw*/匚w"foo bar."中的' bar'?

字符S
意义Q匹配除whiteI格W以外的一个单个的字符Q等价于[^ fnrtv]?
例如Q?S/w*匚w"foo bar."中的'foo'?

字符t
意义Q匹配一个制表符

字符v
意义Q匹配一个顶头制表符

字符w
意义Q匹配所有的数字和字母以及下划线Q等价于[A-Za-z0-9_]?
例如Q?w/匚w"apple,"中的'a'Q?$5.28,"中的'5'?3D."中的'3'?

字符W 
意义Q匹配除数字、字母外及下划线外的其它字符Q等价于[^A-Za-z0-9_]?
例如Q?W/或?[^$A-Za-z0-9_]/匚w"50%."中的'%'?

字符n
意义Q这里的n是一个正整数。匹配一个正则表辑ּ的最后一个子串的n的?计数左圆括号)?

例如Q?apple(,)sorange1/匚w"apple, orange, cherry, peach."中的'apple, orange'Q下?
有一个更加完整的例子?
注意Q如果左圆括号中的数字比n指定的数字还,则n取下一行的八进制escape作ؓ描述?

字符ooctal和xhex
意义Q这里的ooctal是一个八q制的escape|而xhex是一个十六进制的escape|允许在一?
正则表达式中嵌入ASCII码?


当表辑ּ被检查的时候,文字W号提供了编辑正则表辑ּ的方法。利用文字符号可以到正则表?
式保持ؓ常数。例如,如果你在一个@环中使用文字W号来构造一个正则表辑ּQ正则表辑ּ不需q行
反复~译?
正则表达式对象构造器Q例如,new RegExp("ab+c")Q提供正则表辑ּ的运行时~译。当你知道正
则表辑ּ的模式会变化的时候,应该使用构造函敎ͼ或者你不知道正则表辑ּ的模式,而它们是从另?
的源获得的时候,比如q戯入时。一旦你定义好了正则表达式,该正则表辑ּ可在M地方使用Q?
q且可以改变Q你可以使用~译Ҏ来编译一个新的正则表辑ּ以便重新使用?
一个分预先定义的RegExp对象可以在每个窗口中使用Q也是_每个分离的JavascriptU程q?
行以获得自己的RegExp对象。因为每个脚本在一个线E中是不可中断的Q这q保了不同的脚本不会覆
盖RegExp对象的倹{?
预定义的RegExp对象包含的静态属性:input, multiline, lastMatch,lastParen, leftContext, 
rightContext, 以及?1?9。input和multiline属性能被预设。其它静态属性的值是在执行个别正?
表达式对象的exec和testҎ后,且在执行字符串的match和replaceҎ后设|的?

属?
注意RegExp对象的几个属性既有长名字又有短名?象Perl)。这些名字都是指向相同的倹{Perl?
一U编E语aQ而Javascript模仿了它的正则表辑ּ?

属?1, ..., $9
取得匚w的子Ԍ如果有的?

属?_
参考input

属?*
参考multiline

属?&
参考lastMatch

属?+
参考lastParen

属?`
参考leftContext

属?'
参考rightContext

属性constructor
指定用来建立对象原型?

属性global
军_是否试正则表达式是否不能匹配所有的字符Ԍ或者只是与最先的冲突?

属性ignoreCase
军_试图匚w字符串的时候是否忽略大写

属性input
当正则表辑ּ被匹配的时候,为相反的字符丌Ӏ?

属性lastIndex
军_下一ơ匹配从那里开?

属性lastMatch
最后一个匹配的字符

属性lastParen
子串匚w的时候,最后一个parenthesizedQ如果有的话?

属性leftContext
最q一ơ匹配前的子丌Ӏ?

属性multiline
是否在串的多行中搜烦?

属性prototype
允许附加属性到所有的对象

属性rightContext
最q一ơ匹配后的的子串?

属性source
模式文本

 

 

Ҏ
compileҎ
~译一个正则表辑ּ对象

execҎ
q行正则表达式匹?

testҎ
试正则辑ּ匚w

toSourceҎ
q回一个对象的文字描述指定的对象;你可以用这个值来建立一个新的对象。不考虑Object.toS
ourceҎ?

toStringҎ
q回一个字W串描述指定的对象,不考虑Object.toString对象?

valueOfҎ
q回指定对角的原始倹{不考虑Object.valueOfҎ?

 另外Q这个对象承了对象的watch和unwatchҎ

 

  例子Q?
  例1、下q示例脚本用replaceҎ来{换串中的单词。在替换的文本中Q脚本用全局 RegExp
对象?1?2属性的倹{注意,在作为第二个参数传递给replaceҎ的时候,RegExp对象?属性的?
U?
<script LANGUAGE="Javascript1.2">
re = /(w+)s(w+)/;
str = "John Smith";
newstr=str.replace(re,"$2, $1");
document.write(newstr)
</script>
昄l果Q?Smith, John". 

  例2、下q示例脚本中QRegExp.input由Change事g处理句柄讄。在getInfo函数中,exec Ҏ
使用RegExp.input的g为它的参敎ͼ注意RegExp预置?属性?


<script LANGUAGE="Javascript1.2">
function getInfo(abc)
{
re = /(w+)s(d+)/;
re.exec(abc.value);
window.alert(RegExp.$1 + ", your age is " + RegExp.$2);
}
</script>

  误入你的姓和年龄,输入完后按回车键?
  <FORM><INPUT TYPE="TEXT" NAME="NameAge" onChange="getInfo(this);"></FORM>
  </HTML>


$1, ..., $9属?
用圆括号括着的匹配子Ԍ如果有的话?
是RegExp的属?
静态,只读

在Javascript 1.2, NES 3.0以上版本提供
描述Q因为input是静态属性,不是个别正则表达式对象的属性。你可以使用RegExp.input 讉K?
属性?

能加上圆括号的子串的数量不受限制Q但正则表达式对象只能保留最? 条。如果你要访问所有的
圆括号内的匹配字Ԍ你可以用返回的数组?

q些属性能用在RegExp.replaceҎ替换后的字符?输出l果)。当使用q种方式的时候,不用?
先考虑RegExp对象。下面给Z子。当正则表达式中没有包含圆括L时候,该脚本解释成$n的字面意
义?q里的n是一个正整数)?


例如Q?
下例脚本使用replace Ҏ来交换串中单词的位置。在替换后的文本字串中,脚本使用正则表达?
RegExp对象?1?2属性的倹{注意:当它们向replaceҎ传递参数的时候,q里没有考虑 $ 属性的
RegExp对象的名U?
<script LANGUAGE="Javascript1.2">
re = /(w+)s(w+)/;
str = "John Smith";
newstr=str.replace(re,"$2, $1");
document.write(newstr)
</script>
昄的输出结果ؓQSmith, John。?br /> 

正则表达式详qͼ二) 

以下q些不是正则表达式的新增对象请参阅对应的Javascript对象的属?$_属?参考input $*属?
参考multiline $&属?参考lastMatch $+属?参考lastParen $`属?
参考leftContext $'属?参考rightContext compileҎ 在脚本运行期间编译正则表辑ּ对象
属于RegExp的方?在Javascript 1.2, NES 3.0以上版本提供 语法Q?
regexp.compile(pattern[, flags]) 以数Q?regexp 正则表达式的名称Q可以是变量名或文字丌Ӏ?
pattern 正则表达式的定义文本?flags 如果指定的话Q可以是下面其中的一个: "g": 匚w所有可能的字串
"i": 忽略大小?"gi": 匚w所有可能的字串及忽略大写 描述Q?
使用compileҎ来编译一个正则表辑ּ created with the RegExp constructor function。这?
强制正则表辑ּ只编译一ơ,而不是每ơ遇到正则表辑ּ的时候都~译一ơ。当你确认正则表辑ּ?
保持不变的时候可使用compile Ҏ来编译它(在获得它的匹配模式后)Q这样就可以在脚本中重复多次使用它?
你亦可以使用compile Ҏ来改变在q行期间改变正则表达式。例如,假如正则表达式发生变化,
你可以用compileҎ来重新编译该对象来提高用效率?
使用该方法将改变正则表达式的source, global和ignoreCasesource属性的倹{?constructor 
指出建立对象原型的function。注意这个属性的值由函数本n提供Q而不是一个字串包含RegExp的name.Property提供。?
在Javascript 1.1, NES 2.0以上版本提供 ECMA版本ECMA-262 描述Q参考Object.constructor.
execҎ 在指定的字符串运行匹配搜索。返回一个结果数l?是RegExp的方法?
在Javascript 1.2, NES 3.0以上版本提供 语法Q?regexp.exec([str])regexp([str])
参数Q?regexpQ正则表辑ּ的名Uͼ可以是一个变量名或文字定义串。?
strQ要匚w正则表达式的字符Ԍ如果省略Q将使用RegExp.input的倹{?
描述Q就如在语法描述中的一P正则表达工的execҎ能够被直接调?使用regexp.exec(str))或者间接调?使用regexp(str))?
假如你只是运行以扑և是否匚wQ可以用String搜烦Ҏ?
假如匚w成功QexecҎq回一个数lƈ且更新正则表辑ּ对象属性的值和预先定义的正则表辑ּ对象、RegExp。如果匹配失败,execҎq回null?
L下例Q?<script LANGUAGE="Javascript1.2"> //匚w一个b接着一个或多个dQ再接着一个b
//忽略大小?myRe=/d(b+)(d)/ig; myArray = myRe.exec("cdbBdbsbz");
</script> 下面是该脚本的返回|对象 属?Index 描述 例子 
myArray

myArray的内?["dbBd", "bB", "d"] 
index
Z0的匹配index 1 
input
原始字符?cdbBdbsbz 
[0]
最后匹配的字符 dbBd 
[1], ...[n]
用圆括号括住的匹配字W串Q如果有的话。不限制括号的个数?[1] = bB
[2] = d 
myRe
lastIndex
开始下ơ匹配操作的index?5 
ignoreCase
指出"i"是否使用以忽略大写 true 
global
指出是否使用"g"标记来进行匹配所有可能的字串 true 
source
定义模式的文本字W串 d(b+)(d) 
RegExp
lastMatch$&
最后匹配的字符 dbBd 
leftContext$Q
最新匹配前面的子串 c 
rightContext$'
最新匹配后面的子串 bsbz 
$1, ...$9
圆括号内的匹配子Ԍ如果有的话。圆括号的个C受限Ӟ但RegExp只能保留最??$1 = bB 
$2 = d 
lastParen $+
最后一个加上圆括号的匹配子Ԍ如果有的?d 

假如你的正则表达式用了"g"标记Q你可以多次使用exec Ҏ来连l匹配相同的丌Ӏ当你这样做
的时候,新的匚w从由正则表辑ּ的lastIndex 属性值确定的子串中开始。例如,假定你用下面的脚本Q?
<script LANGUAGE="Javascript1.2"> myRe=/ab*/g;str = "abbcdefabh"
myArray = myRe.exec(str);
document.writeln("Found "+myArray[0]+". Next match starts at "+myRe.lastIndex)
mySecondArray = myRe.exec(str);
document.writeln("Found "+mySecondArray[0]+". Next match starts at "+myRe.lastIndex)
</script> q个脚本昄如下l果Q?Found abb. Next match starts at 3
Found ab. Next match starts at 9 例子Q?
在下面的例子中,用户输入一个名字,脚本Ҏ输入执行匚w操作。接着查数l看是否和其它用L名字匚w?
本脚本假定已注册的用L姓已l存q了数组A中,或许从一个数据库中取得?<HTML>
<script LANGUAGE="Javascript1.2"> A = ["zhao","qian","sun","li","liang"]
function lookup() { firstName = /w+/i(); if (!firstName)
window.alert (RegExp.input + "非法输入"); else { count=0;
for (i=0;i 输入你的姓然后按回R键?
<FORM><INPUT TYPE:"TEXT" NAME="FirstName" onChange="lookup(this);"></FORM>
</HTML> global属?正则表达式中是否使用?g"标记?RegExp属性,只读
在Javascript 1.2, NES 3.0以上版本提供 描述Q?global是一个个别正则表辑ּ对象的属?
如果使用?g"标记Qglobal的gؓtrueQ否则ؓ false?g"标记指定正则表达式测试所有可能的匚w?
你不能直接改变该属性的|但可以调用compileҎ来改变它?ignoreCase 查正则表辑ּ是否使用?i"标记
RegExp属性,只读 在Javascript 1.2, NES 3.0以上版本提供 描述Q?
ignoreCase是个别正则表辑ּ对象的一个属性?
如果使用?i"标记Q则q回trueQ否则返回false?i"标记指示在进行匹配的时候忽略大写?
你不能直接改变该属性的|但可以通过调用compileҎ来改变它 input 指出正则表达式要试那个字串?_是这个属性的另一个名字?
RegExp的属性,静?在Javascript 1.2, NES 3.0以上版本提供 
描述Q因为input是静态的Q不是某个个别的正则表达式对象的属性。你也可以?RegExp.input来表C?
如果没有l正则表辑ּ的exec或testҎ提供字符Ԍq且RegExp.input中有|则用它的值来调用该方法?
脚本或浏览器能够预置input属性。如果被预置了g调用exec?testҎ的时候没有提供字W串
则调用exec或test的时候用input的倹{input可以被浏览器以下面的方式讄Q?
当text表单域处理句柄被调用的时候,input被设|ؓ该text输入的字丌Ӏ?
当textarea表单域处理句柄被调用的时候,input被设|ؓtextarea域内输入的字丌Ӏ注意multili
ne亦被讄成true从而能匚w多行文本?当select表单域处理句柄被调用的时候,input被设|成selected text的倹{?
当链接对象的处理句柄被调用的时候,input被设|成<A HREF=...>?lt;/A>之间的字W串?
事g理现句柄处理完毕后,input属性的D清除?lastIndex 可读/可写的一个整数属性,指出下一ơ匹配从哪里开始?
RegExp的属?在Javascript 1.2, NES 3.0以上版本提供 
描述QlastIndex 是个别的正则表达式对象的属性?q个属性只有当正则表达式的"g"标记被用以q行全串匚w的时候才被设|。实行以下规则:
如果lastIndex大小字符串的长度Qregexp.test和regexp.execp|Q且lastIndex被设??
如果lastIndex{于字串的长度且正则表达式匹配空字符Ԍ则正则表辑ּ从lastIndex的位|开始匹配?
如果lastIndex{于字符串的长度且正则表辑ּ不匹配空字符Ԍ则正则表辑ּ不匹配inputQ且lastIndex被置??
否则QlastIndex被设|成最q一ơ匹配的下一炏V?例如Q按下面的顺序执行脚本: re = /(hi)?/g 匚wI字W串 
re("hi") q回["hi", "hi"]QlastIndex|ؓ2 
re("hi") q回[""]Q一个空数组Q它的下标ؓ0的元素就是匹配字W串。在q种情况下,q回I?
串是因ؓlastIndex{于2(且仍然是2)Qƈ?hi"的长度也??lastMatch 最后一ơ匹配字W串Q?&是同L意思?
RegExp的属性,静态,只读 在Javascript 1.2, NES 3.0以上版本提供 
描述Q因为lastMatch是静态的Q所以它不是个别指定正则表达式的属性。你也可以用RegExp.lastMatch?lastParen
最后一ơ加上括L匚w字符Ԍ如果有的话?+是同L意思?RegExp属性,静态,只读
在Javascript 1.2, NES 3.0以上版本提供 
描述Q因为lastParen是静态的Q它不是某个个别正则式的属性,你可以用RegExp.lastParen 表达同样的意思?
leftContext 最q一ơ匹配前面的子串Q?`h相同的意思?RegExp的属性,静态,只读
在Javascript 1.2, NES 3.0以上版本提供 
描述Q因为leftContext是静态的Q不是某一个正则表辑ּ的属性,所以可以用RegExp.leftContext来表达想同的意思?
multiline 反映是否匚w多行文本Q?*是相同的意思?RegExp的属性,静?
在Javascript 1.2, NES 3.0以上版本提供 
描述Q因为multiline是静态的Q而不是某个个别正则表辑ּ的属性,所以能够用RegExp.multiline表达相同的意思?
如果允许匚w多行文本Q则multiline为trueQ如果搜索必d换行时停止,则ؓfalse?
脚本或浏览器能够讄multiline属性。当一个textarea的事件处理句柄被调用的时候,multiline
被置为true。在事g处理句柄处理完毕后,multiline属性D清除。也是_如果你设|了multili
ne为trueQ则执行M的事件处理句柄后Qmultiline被置为false?prototype 
描绘cȝ原型。你可以Ҏ要求使用prototype来增加类的属性或Ҏ。ؓ了获得prototypes 的资
料,请参阅RegExp的function.prototype.Property属性?从Javascript 1.1, NES 2.0版本开始提?
ECMA版本ECMA-262 rightContext 最后一ơ匹配的双的字W串Q?'是同L效果?
RegExp的属性,静态,只读 ?Javascript 1.2, NES 3.0以上版本开始提供?
描述Q因为rightContext是静态的Q不是某个个别正则表辑ַ的属性,可以使用RegExp.rightContext来达到相同的效果?
source 一个只d性,包含正则表达式定义的模式Q不包Lforward slashes?g"?i"标记?RegExp的属性,只读
从Javascript 1.2, NES 3.0以上版本开始提供?
描述Qsource是个别正则表辑ּ对象的属性,你不能直接改变它的|但可以通过调用compile Ҏ来改变它?test
执行指定字符串的正则表达式匹配搜索,q回true或false?RegExp的方?
从Javascript 1.2, NES 3.0以上版本开始提?语法Qregexp.test([str])
参数QregexpQ正则表辑ּ的名Uͼ可以是变量名或正则表辑ּ定义文字?
strQ要匚w的字W串Q如果省略,用RegExp.input的gؓ作参?
描述Q当你需要知道一个字W串能否匚w某个正则表达工,可以使用testҎ(与String.search?
法类?Q?Z获得更多的信?但速度变?Q可以用execҎ(与String.matchҎcM)?例子Q下面的例子昄test是否成功的提C:
function testinput(re, str){
if (re.test(str)) midstring = " contains ";
else midstring = " does not contain ";
document.write (str + midstring + re.source); } toSource 
q回一个字W串象征对象的源?RegExp的方?从Javascript 1.3以上版本开始提?语法QtoSource()
参数Q没?描述QtoSourceҎq回下述的| 对于内置的RegExp对象QtoSourceq回下面的字W象征源码不可用Q?
function Boolean(){ [native code] }
在RegExp场合? toSourceq回象征源码的字W串Q通常q个Ҏ是由Javascript内部自动调用而不是不代码中显式调用?
更多LObject.toSource toString q回描绘指定对象的字W串?RegExp的方?
从Javascript 1.1, NES 2.0开始提?ECMA版本ECMA-262 语法QtoString() 参数Q无
描述QRegExp对象不考虑Object对象的toStringҎQ它不承Object.toStringQ对于RegExp ?
象,toStringҎq回一个代表该对象的字W串?例如Q下面的例子昄象征RegExp对象的字W串
myExp = new RegExp("a+b+c"); alert(myExp.toString())
displays "/a+b+c/" 更多LQObject.toString valueOf q回一个RegExp对象的原始?
RegExp的方?从Javascript 1.1版本开始提?ECMA版本QECMA-262 语法QvalueOf()
参数Q无 描述QRegExp的valueOfҎ以字W串形式q回RegExp对象的原始|q个gRegExp.toString相等?
该方法通常由Javascript内部自动调用而不是显式调?例子Q?myExp = new RegExp("a+b+c");
alert(myExp.valueOf()) displays "/a+b+c/"



]]>
JAVA中正则表辑ּ的应?(一) http://www.tkk7.com/hua/archive/2006/08/30/66737.html?/dc:creator>?/author>Wed, 30 Aug 2006 15:15:00 GMThttp://www.tkk7.com/hua/archive/2006/08/30/66737.htmlhttp://www.tkk7.com/hua/comments/66737.htmlhttp://www.tkk7.com/hua/archive/2006/08/30/66737.html#Feedback0http://www.tkk7.com/hua/comments/commentRss/66737.htmlhttp://www.tkk7.com/hua/services/trackbacks/66737.html

正则表达式:

正则表达式是一U可以用于模式匹配和替换的强有力的工P一个正则表辑ּ是由普通的字符Q例如字W?a ?zQ以及特D字W(UCؓ元字W)l成的文字模式,它描q在查找文字M时待匚w的一个或多个字符丌Ӏ正则表辑ּ作ؓ一个模板,某个字W模式与所搜烦的字W串q行匚w?/p>

正则表达式在字符数据处理中v着非常重要的作用,我们可以用正则表辑ּ完成大部分的数据分析处理工作Q如:判断一个串是否是数字、是否是有效的Email地址Q从量的文字资料中提取有h值的数据{等Q如果不使用正则表达式,那么实现的程序可能会很长Qƈ且容易出错。对q点本h深有体会Q面对大量工具书电子档资料的整理工作Q如果不懂得应用正则表达式来处理Q那么将是很痛苦的一件事情,反之则将可以L地完成,获得事半功倍的效果?/p>

׃本文目的是要介绍如何在JAVA里运用正则表辑ּQ因此对刚接触正则表辑ּ的读者请参考有兌料,在此因篇q有限不作介l?/p>



回页?/font>


JAVAҎ则表辑ּ的支持:

在JDK1.3或之前的JDK版本中ƈ没有包含正则表达式库可供JAVAE序员用,之前我们一般都在用第三方提供的正则表辑ּ库,q些W三方库中有源代码开攄Q也有需付费购买的,而现时在JDK1.4的测试版中也已经包含有正则表辑ּ?--java.util.regex?/p>

故此现在我们有很多面向JAVA的正则表辑ּ库可供选择Q以下我介l两个较具代表性的 Jakarta-ORO?java.util.regexQ首先当然是本h一直在用的 Jakarta-OROQ?/b>





回页?/font>


Jakarta-ORO正则表达式库

1Q简介:

Jakarta-ORO是最全面以及优化得最好的正则表达式API之一QJakarta-ORO库以前叫做OROMatcherQ是由Daniel F. Savarese~写Q后来他其赠与Jakarta ProjectQ读者可在Apache.org的网?下蝲该API包?

许多源代码开攄正则表达式库都是支持Perl5兼容的正则表辑ּ语法QJakarta-ORO正则表达式库也不例外Q他与Perl 5正则表达式完全兼宏V?/p>

2Q对象与其方法:

★PatternCompiler对象Q?
我们在用Jakarta-ORO API包时Q最先要做的是,创徏一个Perl5Compilercȝ实例Qƈ把它赋值给PatternCompiler接口对象。Perl5Compiler是PatternCompiler接口的一个实玎ͼ允许你把正则表达式编译成用来匚w的Pattern对象?

																
																		PatternCompiler compiler=new Perl5Compiler();
																
														

★Pattern对象Q?
要把所对应的正则表辑ּ~译成Pattern对象Q需要调用compiler对象的compile()ҎQƈ在调用参C指定正则表达式。D个例子,你可以按照下面这U方式编译正则表辑ּ"s[ahkl]y"Q?

																
																		 Pattern pattern=null;
        try {
                pattern=compiler.compile("s[ahkl]y ");
        } catch (MalformedPatternException e) {
                e.printStackTrace();
        }
																
														

在默认的情况下,~译器会创徏一个对大小写敏感的模式QpatternQ。因此,上面代码~译得到的模式只匚w"say"?shy"?"sky"?sly"Q但不匹?Say"?skY"。要创徏一个大写不敏感的模式Q你应该在调用编译器的时候指定一个额外的参数:
pattern=compiler.compile("s[ahkl]y",Perl5Compiler.CASE_INSENSITIVE_MASK);

Pattern对象创徏好之后,可以通过PatternMatchercȝ该Pattern对象q行模式匚w?/p>

★PatternMatcher对象:

PatternMatcher对象依据Pattern对象和字W串展开匚w查。你要实例化一个Perl5Matchercdƈ把结果赋值给PatternMatcher接口。Perl5MatchercLPatternMatcher接口的一个实玎ͼ它根据Perl 5正则表达式语法进行模式匹配:
PatternMatcher matcher=new Perl5Matcher();

PatternMatcher对象提供了多个方法进行匹配操作,q些Ҏ的第一个参数都是需要根据正则表辑ּq行匚w的字W串Q?/p>

  1. boolean matches(String input, Pattern pattern)Q当要求输入的字W串input和正则表辑ּpattern_匚w时用该Ҏ。也是说当正则表达式完整地描述输入字符串时q回真倹{?
  2. boolean matchesPrefix(String input, Pattern pattern)Q要求正则表辑ּ匚w输入字符串v始部分时使用该方法。也是说当输入字符串的起始部分与正则表辑ּ匚w时返回真倹{?
  3. boolean contains(String input, Pattern pattern)Q当正则表达式要匚w输入字符串的一部分时用该Ҏ。当正则表达式ؓ输入字符串的子串时返回真倹{?

但以上三U方法只会查找输入字W串中匹配正则表辑ּ的第一个对象,如果当字W串可能有多个子串匹配给定的正则表达式时Q那么你可以在调用上面三个Ҏ时用PatternMatcherInput对象作ؓ参数替代String对象Q这样就可以从字W串中最后一ơ匹配的位置开始l进行匹配,q样方便的多了?/p>

用PatternMatcherInput对象作ؓ参数替代StringӞ上述三个Ҏ的语法如下:

  1. boolean matches(PatternMatcherInput input, Pattern pattern)
  2. boolean matchesPrefix(PatternMatcherInput input, Pattern pattern)
  3. boolean contains(PatternMatcherInput input, Pattern pattern)

★Util.substitute()Ҏ:
查找后需要要q行替换Q我们就要用到Util.substitute()ҎQ其语法如下Q?

																
																		public static String substitute(PatternMatcher matcher,
       Pattern pattern,Substitution sub,String input,
       int numSubs)

																
														

前两个参数分别ؓPatternMatcher和Pattern对象。而第三个参数是个Substiution对象Q由它来军_替换操作如何q行。第四个参数是要q行替换操作的目标字W串Q最后一个参数用来指定是否替换模式的所有匹配子ԌUtil.SUBSTITUTE_ALLQ,或只q行指定ơ数的替换?/p>

在这里我怿有必要详l解说一下第三个参数Substiution对象Q因为它决定替换将怎样q行?/p>

Substiution:
Substiution是一个接口类Q它Z提供了在使用Util.substitute()Ҏ时控制替换方式的手段Q它有两个标准的实现c:StringSubstitution与Perl5Substitution。当Ӟ同时你也可以生成自己的实现类来定制你所需要的Ҏ替换动作?

StringSubstitutionQ?/b>
StringSubstitution 实现的是单的U文字替换手D,它有两个构造方法:

StringSubstitution()->~省的构造方法,初始化一个包含零长度字符串的替换对象?/p>

StringSubstitution(java.lang.String substitution)->初始化一个给定字W串的替换对象?/p>

Perl5SubstitutionQ?/b>
Perl5Substitution 是StringSubstitution的子c,它在实现U文字替换手D늚同时也允许进行针对MATHc里各匹配组的PERL5变量的替换,所以他的替换手D|其直接父cStringSubstitution更ؓ多元化?

它有三个构造器Q?/p>

Perl5Substitution()

Perl5Substitution(java.lang.String substitution)

Perl5Substitution(java.lang.String substitution, int numInterpolations)

前两U构造方法与StringSubstitution一P而第三种构造方法下面将会介l到?/p>

?Perl5Substitution的替换字W串中可以包含用来替代在正则表达式里由小扩号围v来的匚wl的变量Q这些变量是?1, $2,$3{Ş式来标识。我们可以用一个例子来解释怎样使用替换变量来进行替换:

假设我们有正则表辑ּ模式为b\d+:Q也是b[0-9]+:Q,而我们想把所有匹配的字符串中?b"都改?a",?Q?则改?-"Q而其余部分则不作修改Q如我们输入字符串ؓ"EXAMPLE b123:"Q经q替换后应该变?EXAMPLE a123-"。要做到q点Q我们就首先要把不做替换的部分用分组W号括号包hQ这h则表辑ּ变?b(\d+):"Q而构造Perl5Substitution对象时其替换字符串就应该?a$1-"Q也是构造式为Perl5SubstitutionQ?a$1-"Q,表示在用Util.substitute()Ҏ时只要在目标字符串里扑ֈ和正则表辑ּ" b(\d+): "相匹配的子串都用替换字符串来替换Q而变?1表示如果和正则表辑ּ里第一个组相匹配的内容则照般原文插?1所在的为置Q如?EXAMPLE b123Q?中和正则表达式相匚w的部分是"b123Q?Q而其中和W一分组"(\d+)"相匹配的部分则是"123"Q所以最后替换结果ؓ"EXAMPLE a123-"?/p>

有一炚w要清楚的是,如果你把构造器Perl5Substitution(java.lang.String substitution,int numInterpolations)

中的numInterpolations参数设ؓINTERPOLATE_ALLQ那么当每次扑ֈ一个匹配字串时Q替换变量($1Q?2{)所指向的内定wҎ目前匚w字串来更斎ͼ但是如果numInterpolations参数设ؓ一个正整数NӞ那么在替换时只会在前Nơ匹配发生时替换变量会跟随匹配对象来调整所代表的内容,但Nơ之后就以一致以WNơ替换变量所代表内容来做Z后替换结果?/p>

举个例子会更好理解:

假如沿用以上例子中的正则表达式模式以及替换内Ҏq行替换工作Q设目标字符串ؓ"Tank b123: 85 Tank b256: 32 Tank b78: 22"Qƈ且设numInterpolations参数为INTERPOLATE_ALLQ而Util.substitute()Ҏ中的numSub变量设ؓSUBSTITUTE_ALLQ请参考上文Util.substitute()Ҏ内容Q,那么你获得的替换l果会是: Tank a123- 85 Tank a256- 32 Tank a78- 22

但是如果你把numInterpolations设ؓ2Qƈ且numSubs依然设ؓSUBSTITUTE_ALLQ那么这时你获得的结果则会是Q?Tank a123- 85 Tank a256- 32 Tank a256- 22

你要注意到最后一个替换所用变?1所代表的内容与W二?1一样ؓ"256"Q而不是预期的"78"Q因为在替换q行中,替换变量$1只根据匹配内容进行了两次更新Q最后一ơ就使第二次匚w时所更新的结果,那么我们可以由此知道Q如果numInterpolations设ؓ1Q那么结果将是: Tank a123- 85 Tank a123- 32 Tank a123- 22

3Q应用示例:

刚好前段旉公司准备Z个《伊索预a》的p学习互动教材Q其中有电子档资料的整理工作Q我们就以此Z来看一下Jakarta-ORO与JDBC2.0 APIl合hҎ据库内的资料q行单提取与整理的实现。假讄录入部的同事送过来的存放在MS SQLSERVER 7数据库里的电子档的表l构如下Q注Q或许在不同的DBMS中有相应的正则表辑ּ的应用,但这不在本文讨论范围内)Q?/p>

表名QAESOP, 表中每条记录包含有三?
IDQintQ:单词索引?
WORDQvarcharQ:单词
CONTENT(varchar)Q存攑֍词的相关解释与例句等内容

其中CONTENT列中内容的格式如下:
[x] [词性] Q解释){(例句一/例句解释/例句中该词的词? 单词在句中的意? (例句?例句解释/例句中该词的词? 单词在句中的意?}

如对应单词Kevin,CONTENT中的内容如下Q?
['kevin] [名词]Qh名凯文){(Kevin loves comic./凯文爱O?名词: 凯文)( Kevin is living in ZhuHai now./凯文C在珠?名词: 凯文)}

我们的例子主要针对CONTENT列中内容q行字符串处理?/p>

★查扑֍个匹配:
首先Q让我们试把CONTNET列中的[x]字段的内容列C出来,׃所有单词的记录中都有这一ƈ且都在字串开始位|,所以这个查扑ַ作比较简单:

  1. 定相应的正则表辑ּQ\[[^]]+\]

    q个是很单的正则表达式,其意思是要求相匹配的字符串必Mؓ以一对中括号包含的所有内容,如['kevin] 、[名词]{,但内容中不包?]"W号Q也是要避免出?[][]"会作Z个匹配对象的情况出现Q有x则表辑ּ的基知识请参照有兌料,q里不再详述Q?/p>

    注意Q在Java中,你必d每一个向前的斜杠Q?\"Q进行{义处理。所以我们要在上面的正则表达式里每个"\"前面加上一?\"以免出现~译错误Q也是在JAVA中初始化正则表达式的字符串的语句应该为:

    String restring=" \\[[^]]+\\]";

    q且在表辑ּ里每个符号中间不能有I格Q否则就会同样出现编译错误?/p>

  2. 实例化PatternCompiler对象Q创建Pattern对象

    PatternCompiler compiler=new Perl5Compiler();

    Pattern pattern=compiler.compile(restring);

  3. 创徏PatternMatcher对象Q调用PatternMatcher接口的contain()Ҏ查匹配情况:
    																				
    																						  PatternMatcher matcher=new Perl5Matcher();
            if (matcher.contains(content,pattern)) {
                     //处理代码片段
            }
    
    																				
    																		

    q里matcher.contains(content,pattern)中的参数 content是从数据库里取来的字W串变量。该Ҏ只会查到W一个匹配的对象字符Ԍ但是׃x均在CONETNET内容字符串中的v始位|,所以用q个Ҏ已l可以保证把每条记录里的xҎ出来?但更为直接与合理的办法是使用boolean matchesPrefix(PatternMatcherInput input, Pattern pattern)ҎQ该Ҏ验证目标字符串是否以正则表达式所匚w的字串ؓ起始?/p>

    具体实现的完整的E序代码如下Q?/p>
    																				
    																						package RegularExpressions;
    //import…?
    import org.apache.oro.text.regex.*;
    //使用Jakarta-ORO正则表达式库前需要把它加到CLASSPATH里面Q如果用IDE?/JBUILDERQ那么也可以在JBUILDER里直接自建新库?
    
    public class yisuo{
      public static void main(String[] args){
      try{     
    //使用JDBC DRIVERq行DBMSq接Q这里我使用的是一个第三方JDBC 
    //DRIVERQMicrosoft本n也有一个面向SQLSERVER7/2000的免费JDBC //DRIVERQ但其性能真的是奇差,不用也Ş?
            Class.forName("com.jnetdirect.jsql.JSQLDriver");
              Connection con=DriverManager.getConnection
              ("jdbc:JSQLConnect://kevin:1433","kevin chen","re");
              Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
              ResultSet.CONCUR_UPDATABLE);
    //Z用Jakarta-ORO库而创建相应的对象
    String rsstring=" \\[[^]]+\\]"; 
              PatternCompiler orocom=new Perl5Compiler();
              Pattern pattern=orocom.compile(rsstring);
              PatternMatcher matcher=new Perl5Matcher();
              ResultSet uprs = stmt.executeQuery("SELECT * FROM aesop");
              while (uprs.next()) {
    Stirng  word=uprs.getString("word");
              Stirng  content=uprs.getString("content");
                if(matcher.contains(content,pattern)){
              //或if(matcher.matchesPrefix(content,pattern)){
                    MatchResult result=matcher.getMatch();
                    Stirng pure=result.toString();
                    System.out.println(word+"的音标ؓQ?+pure);
                }
              }
           }
      catch(Exception e) {
                 System.out.println(e);
           }
      }
    }
    																				
    																		

    输出l果为:kevin的音标ؓ['kevin]

在这个处理中我是用toString()Ҏ来取得结果,但是如果正则表达式里是用了分l符P圆括PQ那么就可以用group(int gid)的方法来取得相应各组匚w的结果,如正则表辑ּ改ؓ" (\[[^]]+\])"Q那么就可以用以下方法来取得l果Qpure=result.group(0);

用程序验证,输出l果同样为:kevin的音标ؓ['kevin]

而如果正则表辑ּ为(\[[^]]+\]Q(\[[^]]+\]Q,则会查找C个连l的Ҏh包含的内容,也就扑ֈ[x] [词性]两项Q但是两的l果分别在两个组里面Q分别由下面语句获得l果Q?/p>

result.group(0)->q回[x] [词性]两项内容Q也是与整个正则表辑ּ相匹配的l果字符Ԍ在这里也׃ؓ['kevin] [名词]

result.group(1) ->q回[x]内容,l果应是['kevin]

result.group(2) ->q回[词性]内容,l果应是[名词]

l箋用程序验证,发现输出q不正确Q主要是当内Ҏ中文时就不能成功匚wQ考虑到可能是Jakarta-ORO正则表达式库版本不支持中文的问题Q回看一下原来我一直用的还?.0.1的老版本,马上到Jakarta.org上下载最新的2.0.4版本装上再用E序验证Q得出的l果和预期一h?/p>

★查扑֤个匹配:
l过W一步的试使用Jakarta-ORO后,我们已经知道了如何正用该API包来查找目标字符串里一个匹配的子串Q下面我们接着来看一看当目标字符串里包含不止一个匹配的子串时我们如何把它们一个接一个找出来q行相应的处理?

首先我们先试个简单的应用Q假设我们想把CONTNET字段内容里所有用Ҏ号包h的字串都扑և来,很清楚地QCONTNET字段的内定w面就只有两项匚w的内容:[x]?[词性]Q刚才我们其实已l把它们分别扑և来了Q但是我们所用的Ҏ是分l方法,?[x] [词性]"作ؓ一整个正则表达式匹配的内容先找刎ͼ再根据分l把[x]?[词性]分别挑出来。但是现在我们需要做的是把[x]和[词性]分别做ؓ与同一个正则表辑ּ匚w的内容,先找C个接着再找下一个,也就是刚才我们的表达式ؓQ\[[^]]+\]Q(\[[^]]+\]Q?而现在应? \[[^]]+\] "?/p>

我们已经知道在匹配操作的三个Ҏ里只要用PatternMatcherInput对象作ؓ参数替代String对象可以从字符串中最后一ơ匹配的位置开始l进行匹配,实现的程序片D如下:

																
																		PatternMatcherInput input=new PatternMatcherInput(content);
            while (matcher.contains(input,pattern)) {
                result=matcher.getMatch();
                System.out.println(result.group(0)) 
            }

																
														

输出l果?['kevin]
[名词]

接着我们来做复杂一点的处理Q就是我们要先把下面内容Q?
['kevin] [名词]Qh名凯文){(Kevin loves comic./凯文爱O?名词: 凯文)( Kevin is living in ZhuHai now. /凯文C在珠?名词: 凯文)}中的整个例句部分Q也是由大括号所包含的部分)扑և来,再分别把例句一和例句二扑ևQ而各例句中的各项内容Q英文句、中文句、词性、解释)也要分项列出?

W一步当然是要定出相应的正则表达式,需要有两个Q一是和整个例句部分Q也是由大括号包v来的部分Q匹配的正则表达式:"\{.+\}",

另一个则要和每个例句部分匚wQ也是括号中的内容)Q:\(([^)]+\)


而且׃要把例句的各分d来,所以要再把里面的各部分用分l的Ҏ匚w出来Q? ([^(]+)/(.+)/(.+):([^)]+) "?/p>

Z便v见,我们不再和从数据库里dQ而是构造一个包含同样内容的字符串变量,E序片段如下Q?/p>
try{
         String content="['kevin] [名词]Qh名凯文){(Kevin loves comic./凯文爱O?名词:凯文) (Kevin is living in ZhuHai now./凯文C在珠?名词: 凯文)}";
         String ps1="\\{.+\\}";
         String ps2="\\([^)]+\\)";
         String ps3="([^(]+)/(.+)/(.+):([^)]+)";
         String sentence;
         PatternCompiler orocom=new Perl5Compiler();
         Pattern pattern1=orocom.compile(ps1);
         Pattern pattern2=orocom.compile(ps2);
         Pattern pattern3=orocom.compile(ps3);
         PatternMatcher matcher=new Perl5Matcher();
//先找出整个例句部?
            if (matcher.contains(content,pattern1)) {
            MatchResult result=matcher.getMatch();
            String example=result.toString();
            PatternMatcherInput input=new PatternMatcherInput(example);
        //分别扑և例句一和例句二
            while (matcher.contains(input,pattern2)){
                result=matcher.getMatch();
                sentence=result.toString();
        //把每个例句里的各用分组的办法分隔出?
                if (matcher.contains(sentence,pattern3)){
                  result=matcher.getMatch();
                  System.out.println("英文? "+result.group(1));
                  System.out.println("句子中文译: "+result.group(2));
                  System.out.println("词? "+result.group(3));
                  System.out.println("意? "+result.group(4));
                }
            }
        }
       }
  catch(Exception e) {
             System.out.println(e);
       }

输出l果为:
英文? Kevin loves comic.
句子中文译: 凯文爱O?
词? 名词
意? 凯文
英文? Kevin is living in ZhuHai now.
句子中文译: 凯文C在珠?
词? 名词
意? 凯文

★查找替换:
以上的两个应用都是单U在查找字符串匹配方面的Q我们再来看一下查扑֐如何对目标字W串q行替换?

例如我现在想把第二个例句q行改动Q换为:Kevin has seen《LEON》seveal times,because it is a good film./ 凯文已经看过《这个杀手不太冷》几ơ了Q因为它是一部好电媄?名词:凯文?/p>

也就是把
['kevin] [名词]Qh名凯文){(Kevin loves comic./凯文爱O?名词: 凯文)( Kevin is living in ZhuHai now. /凯文C在珠?名词: 凯文)}

改ؓQ?
['kevin] [名词]Qh名凯文){(Kevin loves comic./凯文爱O?名词: 凯文)( Kevin has seen《LEON》seveal times,because it is a good film./ 凯文已经看过《这个杀手不太冷》几ơ了Q因为它是一部好电媄?名词:凯文?}

之前Q我们已l了解Util.substitute()Ҏ与Substiution接口Q以及Substiution的两个实现类StringSubstitution和Perl5SubstitutionQ我们就来看看怎么用Util.substitute()Ҏ配合Perl5Substitution来完成我们上面提出的替换要求Q确定正则表辑ּQ?/p>

我们要先扑ֈ其中的整个例句部分,也就是由大括号包h的字Ԍq且把两个例句分别分l,所以正则表辑ּ为:"\{(\([^)]+\))(\([^)]+\))\}"Q如果用替换变量来代替分l,那么上面的表辑ּ可以看ؓ"\{$1$2\}",q样可以更Ҏ看出替换变量与分l间的关pR?/p>

Ҏ上面的正则表辑ּPerl5Substitutioncd以这h造: Perl5Substitution("{$1( Kevin has seen《LEON》seveal times,because it is a good film./ 凯文已经看过《这个杀手不太冷》几ơ了Q因为它是一部好电媄?名词:凯文?}")

再根据这个Perl5Substitution对象来用Util.substitute()Ҏ便可以完成替换了Q实现的代码片段如下Q?/p>
try{
   String content="['kevin] [名词]Qh名凯文){(Kevin loves comic.
   /凯文爱O?名词: 凯文)(Kevin lives in ZhuHai now./凯文C在珠?名词: 凯文)}";
   String ps1="\\{(\\([^)]+\\))(\\([^)]+\\))\\}";
   String sentence;
   String pure;
   PatternCompiler orocom=new Perl5Compiler();
   Pattern pattern1=orocom.compile(ps1);
   PatternMatcher matcher=new Perl5Matcher();
       String result=Util.substitute(matcher,
        pattern1,new Perl5Substitution(
       "{$1( Kevin has seen《LEON》seveal times,because it is a good film./ 
       凯文已经看过《这个杀手不太冷》几ơ了Q因为它是一部好电媄?名词:凯文?}",1),
        content,Util.SUBSTITUTE_ALL);
        System.out.println(result);
   }
  catch(Exception e) {
             System.out.println(e);
       }

输出l果是正的QؓQ?
['kevin] [名词]Qh名凯文){(Kevin loves comic./凯文爱O?名词: 凯文)( Kevin has seen《LEON》seveal times,because it is a good film./ 凯文已经看过《这个杀手不太冷》几ơ了Q因为它是一部好电媄?名词:凯文?}

至于有关使用numInterpolations参数的构造器用法Q读者只要根据上面的介绍自己动手试一下就会清楚了Q在此就不再例述?/p>



回页?/font>


ȝQ?/font>

本文首先介绍了Jakarta-ORO正则表达式库的对象与ҎQƈ且接着举例让读者对实际应用有进一步的了解Q虽然例子都比较单,但希望读者们在看了该文后对Jakarta-ORO正则表达式库有一定的认知Q在实际工作中有所帮助与启发?/p>

其实在Jakarta org里除了Jakarta-ORO外还有一个百分百的纯JAVA正则表达式库Q就是由Jonathan Locke赠与Jakarta ORG的RegexpQ在该包里面包含了完整的文档以及一个用于调试的Applet例子Q对其有兴趣的读者可以到?下蝲?



]]>
存取E序状态的几种Ҏ--Java I/O应用杂谈http://www.tkk7.com/hua/archive/2006/08/30/66590.html?/dc:creator>?/author>Wed, 30 Aug 2006 02:31:00 GMThttp://www.tkk7.com/hua/archive/2006/08/30/66590.htmlhttp://www.tkk7.com/hua/comments/66590.htmlhttp://www.tkk7.com/hua/archive/2006/08/30/66590.html#Feedback0http://www.tkk7.com/hua/comments/commentRss/66590.htmlhttp://www.tkk7.com/hua/services/trackbacks/66590.html 文gI/OQ文件流→序列化


?b>文g?/b>
    文g操作是最单最直接也是最Ҏ惛_的一U方式,我们说的文g操作不仅仅是通过FileInputStream/FileOutputStreamq么“裸”的方式直接把数据写入到本地文gQ像我以前写的一个扫L游戏JavaMine是q样保存一局的状态的Q,q样比较“底层”了。?br />
主要cMҎ和描qW?br />

  1. FileInputStream.read() //从本地文件读取二q制格式的数据?/font>
  2. FileReader.read() //从本地文件读取字W(文本Q数据?/font>
  3. FileOutputStream.write() //保存二进制数据到本地文g 
  4. FileWriter.write() //保存字符数据到本地文?/font>


?b>XML

    和上面的单纯的I/O方式相比QXML显得“高档”得多,以至于成ZU数据交换的标准。以DOM方式ZQ它兛_的是首先在内存中构造文档树Q数据保存在某个l点上(可以是叶子结点,也可以是标签l点的属性)Q构造好了以后一ơ性的写入到外部文Ӟ但我们只需要知道文件的位置Qƈ不知道I/O是怎么操作的,XML操作方式可能多数Z实践q,所以这里也只列出相关的ҎQ供初学者预先了解一下。主要的包是javax.xml.parsersQ?a >org.w3c.domQ?a >javax.xml.transform。?br />
主要cMҎ和描qW?br />

  1. DocumentBuilderFactory.newDocumentBuilder().parse() //解析一个外部的XML文gQ得C个Document对象的DOM树?/font>
  2. DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() //初始化一DOM树?/font>
  3. Document.getDocumentElement().appendChild() //Z个标{Ҏ加一个子l点 
  4. Document.createTextNode() //生成一个字W串l点 
  5. Node.getChildNodes() //取得某个l点的所有下一层子l点 
  6. Node.removeChild()  //删除某个l点的子l点 
  7. Document.getElementsByTagName() 查找所有指定名U的标签l点 
  8. Document.getElementById() //查找指定名称的一个标{点,如果有多个符合,则返回某一个,通常是第一个?/font>
  9. Element.getAttribute() //取得一个标{某个属性的的值?/font>
  10. Element.setAttribute() //讄一个标{某个属性的的值?/font>
  11. Element.removeAttribute() //删除一个标{某个属性?/font>
  12. TransformerFactory.newInstance().newTransformer().transform() //一DOM树写入到外部XML文g


?b>序列?/b>
    使用基本的文件读写方式存取数据,如果我们仅仅保存相同cd的数据,则可以用同一U格式保存,譬如在我的JavaMine中保存一个盘局Ӟ需要保存每一个方格的坐标、是否有地雷Q是否被d{,q些信息l合成一个“复合类型”;相反Q如果有多种不同cd的数据,那我们要么把它分解成若干部分Q以相同cdQ譬如StringQ保存,要么我们需要在E序中添加解析不同类型数据格式的逻辑Q这很不方ѝ于是我们期望用一U比较“高”的层次上处理数据,E序员应?b>花尽可能的旉和代码对数据q行解析
Q事实上Q序列化操作为我们提供了q样一条途径?br />    序列化(SerializationQ大家可能都有所接触Q它可以把对象以某种特定的编码格式写入或从外部字节流Q即ObjectInputStream/ObjectOutputStreamQ中d。序列化一个对象非怹单,仅仅实现一下Serializable接口卛_Q甚至都不用为它专门dMҎQ?br />

  1. public  class MySerial implements java.io.Serializable
  2. {
  3.   //...
  4. }


但有一个条Ӟ?b>你要序列化的cd中,它的每个属性都必须是是“可序列化”的。这句话说v来有Ҏ口,其实所?b>基本cdQ就是intQcharQboolean之类的)都是“可序列化”的Q而你可以看看JDK文档Q会发现很多cd实已l实CSerializableQ即已经是“可序列化”的了)Q于是这些类的对象以及基本数据类型都可以直接作ؓ你需要序列化的那个类的内部属性。如果碰C不是“可序列化”的属性怎么办?对不P那这个属性的c还需要事先实现Serializable接口Q如此递归Q?b>直到所有属性都是“可序列化”的。?br />
主要cMҎ和描qW?br />

  1. ObjectOutputStream.writeObject() //一个对象序列化到外部字节流 
  2. ObjectInputStream.readObject() //从外部字节流dq新构造对?/font>


    从实际应用上看来Q“Serializable”这个接口ƈ没有定义MҎQ仿佛它只是一个标讎ͼ或者说像是Java的关键字Q而已Q一旦虚拟机看到q个?b>标记”,׃试调用自n预定义的序列化机?/b>Q除非你在实现Serializable接口的同时还定义了私有的readObject()或writeObject()Ҏ。这一点很奇怪。不q你要是不愿意让pȝ使用~省的方式进行序列化Q那必d义上面提到的两个ҎQ?br />

  1. public  class MySerial implements java.io.Serializable
  2. {
  3.   private void writeObject(java.io.ObjectOutputStream out) throws IOException
  4.   {
  5.     //...
  6.   }
  7.   private void readObject(java.io.ObjectInputStream in) throws IOExceptionClassNotFoundException
  8.   {
  9.     //...
  10.   }
  11.   //...


    譬如你可以在上面的writeObject()里调用默认的序列化方法ObjectOutputStream.defaultWriteObject();譬如你不愿意某些敏感的属性和信息序列化,你也可以调用ObjectOutputStream.writeObject()Ҏ明确指定需要序列化那些属性。关于用户可定制的序列化ҎQ我们将在后面提到。?br />
?b>Bean

    上面的序列化只是一U基本应用,你把一个对象序列化到外部文件以后,用notepad打开那个文gQ只能从为数不多的一些可dW中猜到q是有关q个cȝ信息文gQ这需要你熟悉序列化文件的字节~码方式Q那是比较痛苦的(?a >《Core Java 2》第一?/font>里提C相关~码方式Q有兴趣的话可以查看参考资料)Q某些情况下我们可能需要被序列化的文gh更好的可L。另一斚wQ作为Javalg的核心概念?a >JavaBeans”,从JDK 1.4开始,其规范里也要求支持文本方式的?b>长期的持久化”(long-term persistenceQ?br />    打开JDK文档Q?a >java.beans?/font>里的有一个名为?a >Encoder”的c,q就是一个可以序列化bean的实用类。和它相关的两个主要cLXMLEcoder?a >XMLDecoderQ显Ӟq是以XML文g的格式保存和dbean的工兗他们的用法也很单,和上面ObjectOutputStream/ObjectInputStream比较cM。?br />
主要cMҎ和描qW?br />

  1. XMLEncoder.writeObject() //一个对象序列化到外部字节流 
  2. XMLDecoder.readObject() //从外部字节流dq新构造对象?/font>


    如果一个bean是如下格式:

  1. public  class MyBean
  2. {
  3.   int i;
  4.   char[] c;
  5.   String s;
  6.   //...(get和set操作省略)...


那么通过XMLEcoder序列化出来的XML文ghq样的Ş式: 

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.4.0" class="java.beans.XMLDecoder">
  <object class="MyBean">
    <void property="i">
      <int>1</int>
    </void>
    <void property="c">
      <array class="char" length="3">
        <void index="0">
          <int>a</int>
        </void>
        <void index="1">
          <int>b</int>
        </void>
        <void index="2">
          <int>c</int>
        </void>
      </array>
    </void>
    <void property="s">
      <string>fox jump!</string> 
    </void>
  </object>
</java> 

    ?a >AWT?a >Swing中很多可视化lg都是beanQ当然也是可以用q种方式序列化的Q下面就是从JDK文档中摘录的一?a >JFrame序列化以后的XML文gQ?br />
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.0" class="java.beans.XMLDecoder">
  <object class="javax.swing.JFrame">
    <void property="name">
      <string>frame1</string>
    </void>
    <void property="bounds">
      <object class="java.awt.Rectangle">
        <int>0</int>
        <int>0</int>
        <int>200</int>
        <int>200</int>
      </object>
    </void>
    <void property="contentPane">
      <void method="add">
        <object class="javax.swing.JButton">
          <void property="label">
            <string>Hello</string>
          </void>
        </object>
      </void>
    </void>
    <void property="visible">
      <boolean>true</boolean>
    </void>
  </object>
</java> 

    因此但你惌保存的数据是一些不是太复杂的类型的话,把它做成bean再序列化也不׃ؓ一U方便的选择。?br />
?b>Properties
    在以前我ȝ的一关于集合框架的文章里提到q,Properties是历史集合类的一个典型的例子Q这里主要不是介l它的集合特性。大家可能都l常接触一?b>配置文gQ如Windows的ini文gQApache的conf文gQ还有Java里的properties文g{,q些文g当中的数据以“关键字-值”对的方式保存。?b>环境变量”这个概念都知道吧,它也是一U“key-value”对Q以前也常常看到版上问“如何取得系l某某信息”之cȝ问题Q其实很多都保存在环境变量里Q只要用一?br />

  1. System .getProperties().list(System.out); 


p获得全部环境变量的列表: 

-- listing properties --
java.runtime.name=Java(TM) 2 Runtime Environment, Stand...
sun.boot.library.path=C:\Program Files\Java\j2re1.4.2_05\bin
java.vm.version=1.4.2_05-b04
java.vm.vendor=Sun Microsystems Inc.
java.vendor.url=http://java.sun.com/
path.separator=;
java.vm.name=Java HotSpot(TM) Client VM
file.encoding.pkg=sun.io
user.country=CN
sun.os.patch.level=Service Pack 1
java.vm.specification.name=Java Virtual Machine Specification
user.dir=d:\my documents\目\eclipse\SWTDemo
java.runtime.version=1.4.2_05-b04
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
java.endorsed.dirs=C:\Program Files\Java\j2re1.4.2_05\li...
os.arch=x86
java.io.tmpdir=C:\DOCUME~1\cn2lx0q0\LOCALS~1\Temp\
line.separator=

java.vm.specification.vendor=Sun Microsystems Inc.
user.variant=
os.name=Windows XP
sun.java2d.fontpath=
java.library.path=C:\Program Files\Java\j2re1.4.2_05\bi...
java.specification.name=Java Platform API Specification
java.class.version=48.0
java.util.prefs.PreferencesFactory=java.util.prefs.WindowsPreferencesFac...
os.version=5.1
user.home=D:\Users\cn2lx0q0
user.timezone=
java.awt.printerjob=sun.awt.windows.WPrinterJob
file.encoding=GBK
java.specification.version=1.4
user.name=cn2lx0q0
java.class.path=d:\my documents\目\eclipse\SWTDemo\bi...
java.vm.specification.version=1.0
sun.arch.data.model=32
java.home=C:\Program Files\Java\j2re1.4.2_05
java.specification.vendor=Sun Microsystems Inc.
user.language=zh
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixed mode
java.version=1.4.2_05
java.ext.dirs=C:\Program Files\Java\j2re1.4.2_05\li...
sun.boot.class.path=C:\Program Files\Java\j2re1.4.2_05\li...
java.vendor=Sun Microsystems Inc.
file.separator=\
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
sun.cpu.isalist=pentium i486 i386
 

主要cMҎ和描qW?br />

  1. load() //从一个外部流d属性?/font>
  2. store() //属性保存到外部(特别是文Ӟ 
  3. getProperty() //取得一个指定的属性?/font>
  4. setProperty() //讄一个指定的属性?/font>
  5. list() //列出q个Properties对象包含的全部“key-value”对 
  6. System .getProperties() //取得pȝ当前的环境变量?/font>



    你可以这样保存一个properties文gQ?br />

  1. Properties prop = new Properties();
  2. prop.setProperty("key1""value1");
  3. ...
  4. FileOutputStream out = new FileOutputStream("config.properties");
  5. prop.store(out, "--q里是文件头Q可以加入注?-"); 


?b>Preferences
    如果我说Java里面可以不用JNI的手D|作Windows的注册表你信不信Q很多Y件的菜单里都有“Setting”或“Preferences”这L选项用来讑֮或修改Y件的配置Q这些配|信息可以保存到一个像上面所q的配置文g当中Q如果是Windowsq_下,也可能会保存到系l注册表中。从JDK 1.4开始,Java?a >java.util下加入了一个专门处理用户和pȝ配置信息?a >java.util.prefs包,其中一个类Preferences是一U比较“高U”的玩意。从本质上讲QPreferences本n是一个与q_无关的东西,但不同的OS对它的SPIQService Provider InterfaceQ的实现却是与^台相关的Q因此,在不同的pȝ中你可能看到首选项保存为本地文件、LDAP目录V数据库条目{,像在Windowsq_下,它就保存Cpȝ注册表中。不仅如此,你还可以把首选项导出为XML文g或从XML文g导入。?br />
主要cMҎ和描qW?br />

  1. systemNodeForPackage() //Ҏ指定的Class对象得到一个Preferences对象Q这个对象的注册表\径是从“HKEY_LOCAL_MACHINE\”开始的 
  2. systemRoot() //得到以注册表路径HKEY_LOCAL_MACHINE\SOFTWARE\Javasoft\Prefs 为根l点的Preferences对象 
  3. userNodeForPackage() //Ҏ指定的Class对象得到一个Preferences对象Q这个对象的注册表\径是从“HKEY_CURRENT_USER\”开始的 
  4. userRoot() //得到以注册表路径HKEY_CURRENT_USER\SOFTWARE\Javasoft\Prefs 为根l点的Preferences对象 
  5. putXXX() //讄一个属性的|q里XXX可以为基本数值型cdQ如int、long{,但首字母大写Q表C参Cؓ相应的类型,也可以不写而直接用putQ参数则为字W串 
  6. getXXX() //得到一个属性的值?/font>
  7. exportNode() //全部首选项导出Z个XML文g 
  8. exportSubtree() //部分首选项导出Z个XML文g 
  9. importPreferences() //从XML文g导入首选项 


    你可以按如下步骤保存数据Q?br />

  1. Preferences myPrefs1 = Preferences.userNodeForPackage(this);// q种Ҏ是在“HKEY_CURRENT_USER\”下按当前类的\径徏立一个注册表?/font>
  2. Preferences myPrefs2 = Preferences.systemNodeForPackage(this);// q种Ҏ是在“HKEY_LOCAL_MACHINE\”下按当前类的\径徏立一个注册表?/font>
  3. Preferences myPrefs3 = Preferences.userRoot().node("com.jungleford.demo");// q种Ҏ是在“HKEY_CURRENT_USER\SOFTWARE\Javasoft\Prefs\”下按“com\jungleford\demo”的路径建立一个注册表?/font>
  4. Preferences myPrefs4 = Preferences.systemRoot().node("com.jungleford.demo");// q种Ҏ是在“HKEY_LOCAL_MACHINE\SOFTWARE\Javasoft\Prefs\”下按“com\jungleford\demo”的路径建立一个注册表?/font>
  5. myPrefs1.putInt("key1", 10);
  6. myPrefs1.putDouble("key2", -7.15);
  7. myPrefs1.put("key3""value3");
  8. FileOutputStream out = new FileOutputStream("prefs.xml");
  9. myPrefs1.exportNode(out);


 

|络I/OQSocket→RMI


?b>Socket
    Socket~程可能大家都很熟,所以就不多讨论了,只是说通过socket把数据保存到q端服务器或从网lsocketd数据也不׃ؓ一U值得考虑的方式?br />
?b>RMI
    RMI机制其实是RPCQ远E过E调用)的Java版本Q它使用socket作ؓ基本传输手段Q同时也是序列化最重要的一个应用。现在网l传输从~程的角度来看基本上都是以流的方?/b>操作Qsocket是一个例子,对象{换成字节的一个重要目标就是ؓ了方便网l传输?br />    惌一下传l的单机环境下的E序设计Q对于Java语言的函敎ͼҎQ调用(注意与C语言函数调用的区别)的参C递,会有两种情况Q如果是基本数据cdQ这U情况下和C语言是一LQ采?b>g?/b>方式Q如果是对象Q则传递的是对象的引用Q包括返回g是引用,而不是一个完整的对象拯Q试想一下在不同的虚拟机之间q行Ҏ调用Q即使是两个完全同名同类型的对象他们也很可能是不同的引用Q此外对于方法调用过E,׃被调用过E的压栈Q内存“现场”完全被被调用者占有,当被调用Ҏq回Ӟ才将调用者的地址写回到程序计数器QPCQ,恢复调用者的状态,如果是两个虚拟机Q根本不可能用简单压栈的方式来保存调用者的状态。因为种U原因,我们才需要徏立RMI通信实体之间的“代理”对象,譬如“存根”就相当于远E服务器对象在客h上的代理Qstub是q么来的Q当然这是后话了?br />    本地对象与远E对象(未必是物理位|上的不同机器,只要不是在同一个虚拟机内皆为“远E”)之间传递参数和q回|可能有这么几U情形:

  • g递:q又包括两种子情形:如果是基本数据类型,那么都是“可序列化”的Q统l序列化成可传输的字节流Q如果是对象Q而且不是“远E对象”(所谓“远E对象”是实现了java.rmi.Remote接口的对象)Q本来对象传递的应该是引用,但由于上q原因,引用是不以证明对象w䆾的,所以传递的仍然?b>一个序列化的拷?/b>Q当然这个对象也必须满上述“可序列化”的条gQ。?br />
  • 引用传递:可以引用传递的只能是“远E对象”。这里所谓的“引用”不要理解成了真的只是一个符P它其实是一个留在(客户机)本地stub中的Q和q端服务器上那个真实的对象张得一模一L镜像而已Q只是因为它有点“特权”(不需要经q序列化Q,在本地内存里已经有了一个实例,真正引用的其实是q个“孪生子”?/li>


    由此可见Q序列化在RMI当中占有多么重要的地位?br />

数据库I/OQCMP、Hibernate


?b>什么是“Persistence?/b>
    用过VMWare的朋友大概都知道当一个guest OS正在q行的时候点几ZSuspend”将虚拟OS挂vQ它会把整个虚拟内存的内容保存到盘上,譬如你ؓ虚拟OS分配?28M的运行内存,那挂起以后你会在虚拟OS所在的目录下找C个同h128M的文Ӟq就是虚拟OS内存的完整镜像!q种内存的镜像手D其实就是“Persistence”(持久化)概念的由来?br />
?b>CMP和Hibernate

    因ؓ我对J2EE的东西不是太熟悉Q随便找了点材料看看Q所以担心说的不CQ这ơ就不作具体ȝ了,学习……真是一件痛苦的事情[cry]

序列化再探讨


    从以上技术的讨论中我们不难体会到Q序列化是Java之所以能够出色地实现光吹的两大卖点??分布式(distributedQ和跨^収ͼOS independentQ的一个重要基。TIJQ即?a >Thinking in Java”)谈到I/OpȝӞ把序列化UCؓ“lightweight persistence??“轻量的持久化”,q确实很有意思?br />
?b>Z么叫做“序列”化Q?/b>
    开场白里我说更习惯于把“Serialization”称为“序列化”而不是“串行化”,q是有原因的。介l这个原因之前先回顾一些计机基本的知识,我们知道C计算机的内存I间都是U性编址的(什么是“线性”知道吧Q就是一个元素只有一个唯一的“前驱”和唯一的“后l”,当然头尾元素是个例外Q对于地址来说Q它的下一个地址当然不可能有两个Q否则就乱套了)Q“地址”这个概忉|q到数据l构Q就相当于“指针”,q个在本U低q大概q道了。注意了Q既然是U性的Q那“地址”就可以看作是内存空间的“序号”,说明它的l织是有序的,?b>序号”或者说“序列号”正是“Serialization”机制的一U体现。ؓ什么这么说呢?譬如我们有两个对象a和b,分别是类A和B的实例,它们都是可序列化的,而A和B都有一个类型ؓC的属性,Ҏ前面我们说过的原则,C当然也必L可序列化的?br />

  1. import  java.io.*;
  2. ...
  3. class  A implements Serializable
  4. {
  5.   C c;
  6.   ...
  7. }
  8. class  B implements Serializable
  9. {
  10.   C c;
  11.   ...
  12. }
  13. class  C implements Serializable
  14. {
  15.   ...
  16. }
  17. A a;
  18. B b;
  19. C c1;
  20. ...


    注意Q这里我们在实例化a和b的时候,有意让他们的c属性用同一个Ccd对象的引用,譬如c1Q那么请试想一下,但我们序列化a和b的时候,它们的c属性在外部字节(当然可以不仅仅是文gQ里保存的是一份拷贝还是两份拷贝呢Q序列化在这里用的是一U?b>cM于“指针”的ҎQ它为每个被序列化的对象标上一个?b>序列?/b>”(serial numberQ,但序列化一个对象的时候,如果其某个属性对象是已经被序列化的,那么q里只向输出写入该属性的序列P从字节流恢复被序列化的对象时Q也Ҏ序列h到对应的来恢复。这是“序列化”名U的由来Q这里我们看到“序列化”和“指针”是极相似的Q只不过“指针”是内存I间的地址链,而序列化用的?b>外部中的“序列号䏀?/b>?br />    使用“序列号”而不是内存地址来标识一个被序列化的对象Q是因ؓ从流中恢复对象到内存Q其地址可能未必是原来的地址??我们需要的只是q些对象之间的引用关p,而不是死板的原始位置Q这在RMI中就更是必要Q在两台不同的机器之间传递对象()Q根本就不可能指望它们在两台机器上都h相同的内存地址。?br />
?b>更灵zȝ“序列化”:transient属性和Externalizable
    Serializable实很方便,方便C几乎不需要做M额外的工作就可以L内存中的对象保存到外部。但有两个问题得Serializable的威力收到束~:
    一个是效率问题Q《Core Java 2》中指出QSerializable使用pȝ默认的序列化机制会媄响Y件的q行速度Q因为需要ؓ每个属性的引用~号和查P再加上I/O操作的时_I/O和内存读写差的可是一个数量的大)Q其代h当然是可观的?br />    另一个困扰是“裸”的Serializable不可定制Q傻乎乎C么都l你序列化了Q不你是不是想q么做。其实你可以有至三U定制序列化的选择。其中一U前面已l提CQ就是在implements Serializable的类里面dU有的writeObject()和readObject()ҎQ这USerializable׃怺Q?img height="20" alt="[:E]" src="http://www.javaresearch.org/faces/13.gif" width="20" border="0" />Q,在这两个Ҏ里,该序列化什么,不该序列化什么,那就׃说了了Q你当然可以在这两个Ҏ体里面分别调用ObjectOutputStream.defaultWriteObject()和ObjectInputStream.defaultReadObject()仍然执行默认的序列化动作Q那你在代码上不做无用功了Q呵呵)Q也可以用ObjectOutputStream.writeObject()和ObjectInputStream.readObject()Ҏ对你中意的属性进行序列化。但虚拟Z看到你定义了q两个方法,它就不再用默认的机制了?br />    如果仅仅Z跌某些属性不让它序列化,上面的动作似乎显得麻烦,更简单的Ҏ是对不想序列化的属性加?b>transient关键字,说明它是个“暂态变量”,默认序列化的时候就不会把这些属性也塞到外部里了。当Ӟ你如果定义writeObject()和readObject()Ҏ的化Q仍然可以把暂态变量进行序列化。题外话Q像transient?b>violate?b>finallyq样的关键字初学者可能会不太重视Q而现在有的公司招聘就偏偏喜欢问这L问题 :(
    再一个方案就是不实现Serializable而改成实?a >Externalizable接口。我们研I一下这两个接口的源代码Q发现它们很cMQ甚臛_易؜淆。我们要C的是QExternalizable默认q?b>不保存Q何对象相关信?/b>QQ何保存和恢复对象的动作都是你自己定义的。Externalizable包含两个public的方法:

  1. public  void writeExternal(ObjectOutput out) throws IOException;
  2. public  void readExternal(ObjectInput in) throws IOExceptionClassNotFoundException;


    乍一看这和上面的writeObject()和readObject()几乎差不多,但Serializable和Externalizable走的是两个不同的程QSerializable在对象不存在的情况下Q就可以仅凭外部的字节序列把整个对象重徏出来Q但Externalizable在重建对象时Q先是调用该cȝ默认构造函敎ͼ即不含参数的那个构造函敎ͼ使得内存中先有这么一个实例,然后再调用readExternalҎ对实例中的属性进行恢复,因此Q如果默认构造函C和readExternalҎ中都没有赋值的那些属性,特别他们是非基本cd的话Q将会是I(nullQ。在q里需要注意的是,transient只能用在对Serializable而不是Externalizable的实现里?/b>。?br />
?b>序列化与克隆

    从“可序列化”的递归定义来看Q一个序列化的对象貌似对象内存映象的外部克隆Q如果没有共享引用的属性的化,那么应该是一?b>深度克隆。关于克隆的话题有可以谈很多Q这里就不细说了Q有兴趣的话可以参?a >IBM developerWorks上的一文章:JAVA中的指针,引用及对象的clone

一点启C?/u>


    作ؓ一个实际的应用Q我在写那个易的邮g客户端JExp的时候曾l对比过好几U保存Message对象Q主要是几个关键属性和邮g的内容)到本地的ҎQ譬如XML、Properties{,最后还是选择了用序列化的方式Q因U方法最单, 大约可算是“学以致用”Ş。这里“存取程序状态”其实只是一个引子话题Ş了,我想说的??如同前面我们讨论的关于logging的话题一??在Java面前对同一个问题你可以有很多种solutionQ熟悉文件操作的Q你可能会觉得Properties、XML或Bean比较方便Q然后又发现了还有Preferencesq么一个东东,大概又会感慨“天外有天”了Q等C接触了很多种新方法以后,l果又会“殊途同归”,重新反省Serialization机制本n。这不仅是JavaQ科学也是同L道理?/p>

]]>java中的旉操作和格式化http://www.tkk7.com/hua/archive/2006/07/21/59459.html?/dc:creator>?/author>Fri, 21 Jul 2006 09:24:00 GMThttp://www.tkk7.com/hua/archive/2006/07/21/59459.htmlhttp://www.tkk7.com/hua/comments/59459.htmlhttp://www.tkk7.com/hua/archive/2006/07/21/59459.html#Feedback0http://www.tkk7.com/hua/comments/commentRss/59459.htmlhttp://www.tkk7.com/hua/services/trackbacks/59459.html一、获取当前时?/p>

有两U方式可以获得,W一U,使用DatecR?/p>

j2SE的包里有两个Datec,一个是java.sql.Date,一个是java.util.Date

q里Q要使用java.util.Date。获取当前时间的代码如下

Date date = new Date();

date.getTime();

q有一U方式,使用System.currentTimeMillis();

q两U方式获得的l果是一LQ都是得C个当前的旉的long型的旉的毫U|q个值实际上是当前时间g1970q一月一号零旉分零U相差的毫秒数?/p>

当前的时间得CQ但实际的应用中最后往往不是要用q个long型的东西Q用户希望得到的往往是一个时间的字符Ԍ比如?006q??8号”,或?006-06-18”,老外可能希望得到的是?6-18-2006”,诸如此类{等。这是下一个要解决的问?/p>

二、获取某个时间的某种格式

获取旉的格式,需要用C个专门用于时间格式的cjava.text.SimpleDateFormat?/p>

首先Q定义一个SimpleDateFormat变量

SimpleDateFormat sdf = new SimpleDateFormat("",Locale.SIMPLIFIED_CHINESE);

q个构造函数的定义如下Q?/p>

SimpleDateFormat(String pattern, Locale locale)

W一个参数patternQ我们后面再解释Q这里我们用一?",W二个参敎ͼ是用来设|时区的Q这里用Cjava.util.Localeq个c,q个cM面定义了很多静态变量,直接拿过来用OKQ我们把时区讄为Locale.SIMPLIFIED_CHINESEQ只看名字,q个静态变量的意义已经很清楚了?/p>

接下来我们用这个SimpleDateFormat把当前时间格式化Z个如下格式的旉字符东yXXXXqXX月XX日_XX时XX分XXU”,代码Q?/p>

sdf.applyPattern("yyyyqMM月dd日_HH时mm分ssU?);

String timeStr = sdf.format(new Date());

获取旉格式的函数是formatQ这个函数的参数是java.util.Date对象Q这个没有什么花头?/p>

要说明一下的是这个patternQ所谓的模式。这里,yyyy,MM,dd{,q就是模式?/p>

我们可以在SimpleDateFormat的构造函C指定模式Q比?/p>

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd",Locale.SIMPLIFIED_CHINESE);

也可以获取时间格式的时候用applyPattern函数临时指定Q上面的例子是q样?/p>

什么字W代表什么,q是j2seU定好的Q设|模式的时候,我们可以使用U定好的字符加上M我们惌的字W串?/p>

j2se对字W所代表的模式的U定列表如下Q?/p>

 
LetterDate or Time ComponentPresentation
GEra designator Text
yYear Year
M Month in year Month
w Week in year Number
W Week in month Number
D Day in yearNumber
d Day in month Number
F Day of week in month Number
E Day in week Text
a Am/pm marker Text 
H Hour in day (0-23)Number
k Hour in day (1-24)Number
K Hour in am/pm (0-11) Number
h  Hour in am/pm (1-12) Number
m  Minute in hour Number
s  Second in minute Number
S  Millisecond Number  
z  Time zone  General time zone 
Z  Time zone RFC 822 time zone 



]]>
关于Java文g路径问题http://www.tkk7.com/hua/archive/2006/06/27/55268.html?/dc:creator>?/author>Tue, 27 Jun 2006 02:12:00 GMThttp://www.tkk7.com/hua/archive/2006/06/27/55268.htmlhttp://www.tkk7.com/hua/comments/55268.htmlhttp://www.tkk7.com/hua/archive/2006/06/27/55268.html#Feedback0http://www.tkk7.com/hua/comments/commentRss/55268.htmlhttp://www.tkk7.com/hua/services/trackbacks/55268.html

1.如何获得当前文g路径

常用Q?/font>

字符串类型:System.getProperty("user.dir");

l合Q?/font>

package com.zcjl.test.base;
import java.io.File;
public class Test {
    public static void main(String[] args) throws Exception {
        System.out.println(
            Thread.currentThread().getContextClassLoader().getResource(""));
        System.out.println(Test.class.getClassLoader().getResource(""));
        System.out.println(ClassLoader.getSystemResource(""));
        System.out.println(Test.class.getResource(""));
        System.out.println(Test.class.getResource("/"));
        System.out.println(new File("").getAbsolutePath());
        System.out.println(System.getProperty("user.dir"));

    }
}

2.Web服务?/font>

(1).Weblogic

WebApplication的系l文件根目录是你的weblogic安装所在根目录?br />例如Q如果你的weblogic安装在c:\bea\weblogic700.....
那么Q你的文件根路径是c:\.
所以,有两U方式能够让你访问你的服务器端的文gQ?br />a.使用l对路径Q?br />比如你的参数文件放在c:\yourconfig\yourconf.propertiesQ?br />直接使用 new FileInputStream("yourconfig/yourconf.properties");
b.使用相对路径Q?br />相对路径的根目录是你的webapplication的根路径Q即WEB-INF的上一U目录,你的参数文件放在yourwebapp\yourconfig\yourconf.propertiesQ?br />q样使用Q?br />new FileInputStream("./yourconfig/yourconf.properties");
q两U方式均可,自己选择?/font>

(2).Tomcat

在类中输出System.getProperty("user.dir");昄的是%Tomcat_Home%/bin

(3).Resin

不是你的JSP攄相对路径,是JSP引擎执行q个JSP~译成SERVLET
的\径ؓ?比如用新建文件法试File f = new File("a.htm");
q个a.htm在resin的安装目录下

(4).如何ȝ对\径哪Q?/font>

在Java文g中getResource或getResourceAsStream均可

例:getClass().getResourceAsStream(filePath);//filePath可以?/filename",q里?代表web发布根\径下WEB-INF/classes

(5).获得文g真实路径

string  file_real_path=request.getRealPath("mypath/filename"); 

通常使用request.getRealPath("/"); 

3.文g操作的类

import java.io.*;
import java.net.*;
import java.util.*;
//import javax.swing.filechooser.*;
//import org.jr.swing.filter.*;

/**
* 此类中封装一些常用的文g操作?br />* 所有方法都是静态方法,不需要生成此cȝ实例Q?br />* 为避免生成此cȝ实例Q构造方法被x为privatecd的?br />* @since  0.1
*/

public class FileUtil {
  /**
   * U有构造方法,防止cȝ实例化,因ؓ工具cM需要实例化?br />   */
  private FileUtil() {

  }

  /**
   * 修改文g的最后访问时间?br />   * 如果文g不存在则创徏该文件?br />   * <b>目前q个Ҏ的行为方式还不稳定,主要是方法有些信息输出,q些信息输出是否保留q在?/font>

虑中?lt;/b>
   * @param file 需要修Ҏ后访问时间的文g?br />   * @since  0.1
   */
  public static void touch(File file) {
    long currentTime = System.currentTimeMillis();
    if (!file.exists()) {
      System.err.println("file not found:" + file.getName());
      System.err.println("Create a new file:" + file.getName());
      try {
        if (file.createNewFile()) {
        //  System.out.println("Succeeded!");
        }
        else {
        //  System.err.println("Create file failed!");
        }
      }
      catch (IOException e) {
      //  System.err.println("Create file failed!");
        e.printStackTrace();
      }
    }
    boolean result = file.setLastModified(currentTime);
    if (!result) {
    //  System.err.println("touch failed: " + file.getName());
    }
  }

  /**
   * 修改文g的最后访问时间?br />   * 如果文g不存在则创徏该文件?br />   * <b>目前q个Ҏ的行为方式还不稳定,主要是方法有些信息输出,q些信息输出是否保留q在?/font>

虑中?lt;/b>
   * @param fileName 需要修Ҏ后访问时间的文g的文件名?br />   * @since  0.1
   */
  public static void touch(String fileName) {
    File file = new File(fileName);
    touch(file);
  }

  /**
   * 修改文g的最后访问时间?br />   * 如果文g不存在则创徏该文件?br />   * <b>目前q个Ҏ的行为方式还不稳定,主要是方法有些信息输出,q些信息输出是否保留q在?/font>

虑中?lt;/b>
   * @param files 需要修Ҏ后访问时间的文g数组?br />   * @since  0.1
   */
  public static void touch(File[] files) {
    for (int i = 0; i < files.length; i++) {
      touch(files);
    }
  }

  /**
   * 修改文g的最后访问时间?br />   * 如果文g不存在则创徏该文件?br />   * <b>目前q个Ҏ的行为方式还不稳定,主要是方法有些信息输出,q些信息输出是否保留q在?/font>

虑中?lt;/b>
   * @param fileNames 需要修Ҏ后访问时间的文g名数l?br />   * @since  0.1
   */
  public static void touch(String[] fileNames) {
    File[] files = new File[fileNames.length];
    for (int i = 0; i < fileNames.length; i++) {
      files = new File(fileNames);
    }
    touch(files);
  }

  /**
   * 判断指定的文件是否存在?br />   * @param fileName 要判断的文g的文件名
   * @return 存在时返回trueQ否则返回false?br />   * @since  0.1
   */
  public static boolean isFileExist(String fileName) {
    return new File(fileName).isFile();
  }

  /**
   * 创徏指定的目录?br />   * 如果指定的目录的父目录不存在则创建其目录书上所有需要的父目录?br />   * <b>注意Q可能会在返回false的时候创建部分父目录?lt;/b>
   * @param file 要创建的目录
   * @return 完全创徏成功时返回trueQ否则返回false?br />   * @since  0.1
   */
  public static boolean makeDirectory(File file) {
    File parent = file.getParentFile();
    if (parent != null) {
      return parent.mkdirs();
    }
    return false;
  }

  /**
   * 创徏指定的目录?br />   * 如果指定的目录的父目录不存在则创建其目录书上所有需要的父目录?br />   * <b>注意Q可能会在返回false的时候创建部分父目录?lt;/b>
   * @param fileName 要创建的目录的目录名
   * @return 完全创徏成功时返回trueQ否则返回false?br />   * @since  0.1
   */
  public static boolean makeDirectory(String fileName) {
    File file = new File(fileName);
    return makeDirectory(file);
  }

  /**
   * 清空指定目录中的文g?br />   * q个Ҏ尽可能删除所有的文gQ但是只要有一个文件没有被删除都会q回false?br />   * 另外q个Ҏ不会q代删除Q即不会删除子目录及其内宏V?br />   * @param directory 要清I的目录
   * @return 目录下的所有文仉被成功删除时q回trueQ否则返回false.
   * @since  0.1
   */
  public static boolean emptyDirectory(File directory) {
    boolean result = false;
    File[] entries = directory.listFiles();
    for (int i = 0; i < entries.length; i++) {
      if (!entries.delete()) {
        result = false;
      }
    }
    return true;
  }

  /**
   * 清空指定目录中的文g?br />   * q个Ҏ尽可能删除所有的文gQ但是只要有一个文件没有被删除都会q回false?br />   * 另外q个Ҏ不会q代删除Q即不会删除子目录及其内宏V?br />   * @param directoryName 要清I的目录的目录名
   * @return 目录下的所有文仉被成功删除时q回trueQ否则返回false?br />   * @since  0.1
   */
  public static boolean emptyDirectory(String directoryName) {
    File dir = new File(directoryName);
    return emptyDirectory(dir);
  }

  /**
   * 删除指定目录及其中的所有内宏V?br />   * @param dirName 要删除的目录的目录名
   * @return 删除成功时返回trueQ否则返回false?br />   * @since  0.1
   */
  public static boolean deleteDirectory(String dirName) {
    return deleteDirectory(new File(dirName));
  }

  /**
   * 删除指定目录及其中的所有内宏V?br />   * @param dir 要删除的目录
   * @return 删除成功时返回trueQ否则返回false?br />   * @since  0.1
   */
  public static boolean deleteDirectory(File dir) {
    if ( (dir == null) || !dir.isDirectory()) {
      throw new IllegalArgumentException("Argument " + dir +
                                         " is not a directory. ");
    }

    File[] entries = dir.listFiles();
    int sz = entries.length;

    for (int i = 0; i < sz; i++) {
      if (entries.isDirectory()) {
        if (!deleteDirectory(entries)) {
          return false;
        }
      }
      else {
        if (!entries.delete()) {
          return false;
        }
      }
    }

    if (!dir.delete()) {
      return false;
    }
    return true;
  }


  /**
   * q回文g的URL地址?br />   * @param file 文g
   * @return 文g对应的的URL地址
   * @throws MalformedURLException
   * @since  0.4
   * @deprecated 在实现的时候没有注意到FilecLw带一个toURLҎ文件\径{换ؓURL?br />   *             请用File.toURLҎ?br />   */
  public static URL getURL(File file) throws MalformedURLException {
    String fileURL = "file:/" + file.getAbsolutePath();
    URL url = new URL(fileURL);
    return url;
  }

  /**
   * 从文件\径得到文件名?br />   * @param filePath 文g的\径,可以是相对\径也可以是绝对\?br />   * @return 对应的文件名
   * @since  0.4
   */
  public static String getFileName(String filePath) {
    File file = new File(filePath);
    return file.getName();
  }

  /**
   * 从文件名得到文gl对路径?br />   * @param fileName 文g?br />   * @return 对应的文件\?br />   * @since  0.4
   */
  public static String getFilePath(String fileName) {
    File file = new File(fileName);
    return file.getAbsolutePath();
  }

  /**
   * DOS/Windows格式的\径{换ؓUNIX/Linux格式的\径?br />   * 其实是\径中?\"全部换ؓ"/"Q因为在某些情况下我们{换ؓq种方式比较方便Q?br />   * 某中E度上说"/"?\"更适合作ؓ路径分隔W,而且DOS/Windows也将它当作\径分隔符?br />   * @param filePath 转换前的路径
   * @return 转换后的路径
   * @since  0.4
   */
  public static String toUNIXpath(String filePath) {
    return filePath.replace('\\', '/');
  }

  /**
   * 从文件名得到UNIX风格的文件绝对\径?br />   * @param fileName 文g?br />   * @return 对应的UNIX风格的文件\?br />   * @since  0.4
   * @see #toUNIXpath(String filePath) toUNIXpath
   */
  public static String getUNIXfilePath(String fileName) {
    File file = new File(fileName);
    return toUNIXpath(file.getAbsolutePath());
  }

  /**
   * 得到文g的类型?br />   * 实际上就是得到文件名中最后一个?”后面的部分?br />   * @param fileName 文g?br />   * @return 文g名中的类型部?br />   * @since  0.5
   */
  public static String getTypePart(String fileName) {
    int point = fileName.lastIndexOf('.');
    int length = fileName.length();
    if (point == -1 || point == length - 1) {
      return "";
    }
    else {
      return fileName.substring(point + 1, length);
    }
  }

  /**
   * 得到文g的类型?br />   * 实际上就是得到文件名中最后一个?”后面的部分?br />   * @param file 文g
   * @return 文g名中的类型部?br />   * @since  0.5
   */
  public static String getFileType(File file) {
    return getTypePart(file.getName());
  }

  /**
   * 得到文g的名字部分?br />   * 实际上就是\径中的最后一个\径分隔符后的部分?br />   * @param fileName 文g?br />   * @return 文g名中的名字部?br />   * @since  0.5
   */
  public static String getNamePart(String fileName) {
    int point = getPathLsatIndex(fileName);
    int length = fileName.length();
    if (point == -1) {
      return fileName;
    }
    else if (point == length - 1) {
      int secondPoint = getPathLsatIndex(fileName, point - 1);
      if (secondPoint == -1) {
        if (length == 1) {
          return fileName;
        }
        else {
          return fileName.substring(0, point);
        }
      }
      else {
        return fileName.substring(secondPoint + 1, point);
      }
    }
    else {
      return fileName.substring(point + 1);
    }
  }

  /**
   * 得到文g名中的父路径部分?br />   * 对两U\径分隔符都有效?br />   * 不存在时q回""?br />   * 如果文g名是以\径分隔符l尾的则不考虑该分隔符Q例?/path/"q回""?br />   * @param fileName 文g?br />   * @return 父\径,不存在或者已l是父目录时q回""
   * @since  0.5
   */
  public static String getPathPart(String fileName) {
    int point = getPathLsatIndex(fileName);
    int length = fileName.length();
    if (point == -1) {
      return "";
    }
    else if (point == length - 1) {
      int secondPoint = getPathLsatIndex(fileName, point - 1);
      if (secondPoint == -1) {
        return "";
      }
      else {
        return fileName.substring(0, secondPoint);
      }
    }
    else {
      return fileName.substring(0, point);
    }
  }

  /**
   * 得到路径分隔W在文g路径中首ơ出现的位置?br />   * 对于DOS或者UNIX风格的分隔符都可以?br />   * @param fileName 文g路径
   * @return 路径分隔W在路径中首ơ出现的位置Q没有出现时q回-1?br />   * @since  0.5
   */
  public static int getPathIndex(String fileName) {
    int point = fileName.indexOf('/');
    if (point == -1) {
      point = fileName.indexOf('\\');
    }
    return point;
  }

  /**
   * 得到路径分隔W在文g路径中指定位|后首次出现的位|?br />   * 对于DOS或者UNIX风格的分隔符都可以?br />   * @param fileName 文g路径
   * @param fromIndex 开始查扄位置
   * @return 路径分隔W在路径中指定位|后首次出现的位|,没有出现时返?1?br />   * @since  0.5
   */
  public static int getPathIndex(String fileName, int fromIndex) {
    int point = fileName.indexOf('/', fromIndex);
    if (point == -1) {
      point = fileName.indexOf('\\', fromIndex);
    }
    return point;
  }

  /**
   * 得到路径分隔W在文g路径中最后出现的位置?br />   * 对于DOS或者UNIX风格的分隔符都可以?br />   * @param fileName 文g路径
   * @return 路径分隔W在路径中最后出现的位置Q没有出现时q回-1?br />   * @since  0.5
   */
  public static int getPathLsatIndex(String fileName) {
    int point = fileName.lastIndexOf('/');
    if (point == -1) {
      point = fileName.lastIndexOf('\\');
    }
    return point;
  }

  /**
   * 得到路径分隔W在文g路径中指定位|前最后出现的位置?br />   * 对于DOS或者UNIX风格的分隔符都可以?br />   * @param fileName 文g路径
   * @param fromIndex 开始查扄位置
   * @return 路径分隔W在路径中指定位|前最后出现的位置Q没有出现时q回-1?br />   * @since  0.5
   */
  public static int getPathLsatIndex(String fileName, int fromIndex) {
    int point = fileName.lastIndexOf('/', fromIndex);
    if (point == -1) {
      point = fileName.lastIndexOf('\\', fromIndex);
    }
    return point;
  }

  /**
   * 文件名中的cd部分L?br />   * @param filename 文g?br />   * @return Lcd部分的结?br />   * @since  0.5
   */
  public static String trimType(String filename) {
    int index = filename.lastIndexOf(".");
    if (index != -1) {
      return filename.substring(0, index);
    }
    else {
      return filename;
    }
  }
  /**
   * 得到相对路径?br />   * 文g名不是目录名的子节点时返回文件名?br />   * @param pathName 目录?br />   * @param fileName 文g?br />   * @return 得到文g名相对于目录名的相对路径Q目录下不存在该文g时返回文件名
   * @since  0.5
   */
  public static String getSubpath(String pathName,String fileName) {
    int index = fileName.indexOf(pathName);
    if (index != -1) {
      return fileName.substring(index + pathName.length() + 1);
    }
    else {
      return fileName;
    }
  }

}
 4.遗留问题

目前new FileInputStream()只会使用l对路径Q相Ҏ用过Q因相对于web服务器地址Q比较麻?/font>

q不如写个配|文件来的快?/font>

5.按Java文gcd分类d配置文g

配置文g是应用系l中不可~少的,可以增加E序的灵zL。java.util.Properties是从jdk1.2有的类Q一直到现在都支持load ()ҎQjdk1.4以后save(output,string) ->store(output,string)。如果只是单U的读,Ҏ不存在烦恼的问题。web层可以通过 Thread.currentThread().getContextClassLoader().
getResourceAsStream("xx.properties") 获取QApplication可以通过new FileInputStream("xx.properties");直接在classes一U获取。关键是有时我们需要通过web修改配置文gQ我们不能将路径写死了。经q测试觉得有以下心得Q?/font>

1.servlet中读写。如果运用Struts 或者Servlet可以直接在初始化参数中配|,调用时根据servlet的getRealPath("/")获取真实路径Q再ҎString file = this.servlet.getInitParameter("abc");获取相对的WEB-INF的相对\径?br />例:
InputStream input = Thread.currentThread().getContextClassLoader().
getResourceAsStream("abc.properties");
Properties prop = new Properties();
prop.load(input);
input.close();
OutputStream out = new FileOutputStream(path);
prop.setProperty("abc", “test");
prop.store(out, “–test?);
out.close();

2.直接在jsp中操作,通过jsp内置对象获取可操作的l对地址?br />例:
// jsp面
String path = pageContext.getServletContext().getRealPath("/");
String realPath = path+"/WEB-INF/classes/abc.properties";

//java E序
InputStream in = getClass().getClassLoader().getResourceAsStream("abc.properties"); // abc.properties攑֜webroot/WEB-INF/classes/目录?br />prop.load(in);
in.close();

OutputStream out = new FileOutputStream(path); // path为通过面传入的\?br />prop.setProperty("abc", “abcccccc");
prop.store(out, “–test?);
out.close();

3.只通过JavaE序操作资源文g
InputStream in = new FileInputStream("abc.properties"); // 攑֜classes同

OutputStream out = new FileOutputStream("abc.properties");



]]>
վ֩ģ壺 ٸƷһѶ̬| ޾Ʒav߹ۿ| һƵ| ŷxƵ| ޹ҹɫ߹ۿ| պŷcom91tv| ҹˬˬˬWWWƵʮ˽| Ƭ߹ۿѹۿӰ| ѹۿþþƵ| WWWѹۿƵ| þþƷavƷ| jizz| Ƶ߲| avɫӰ| þ91˳ɵӰվ| þþƷ| ѹ߹ۿӰԺ| õƵƵ| Ļ벻Ƶ| ƷѾþþþþþ| 57paoһ| 99ֻоƷƵѹۿ17| ȾþǾƷ6ѹۿ| ɫƵ| aëƬ߲| 99ƷƵ| ŮͬëƬ߲| Ƭѿ| 99Ƶѹۿ| ҹѿƬڵ| һѵӰ| йɫվ| aëƬ100ѹۿ| þþžAVѾƷ| 99ֻоƷƵѹۿ17| 2021ھƷþþþþ| 91ɫƷ| Ļ4| ȫAëƬѿվ| Ƶѹ| ޳avƬþ|