第八章 字串處理

      在〈第八章 字串處理〉中尚無留言

String Processing

目的

從command line讀取資料
搜尋字串
Parse strings
StringBuilder
正規法搜尋
正規法Parse string
正規法取代字串

命令列參數

java TestArgs arg1 arg2 “another arg”, 每個命令列參數, 都放置在陣列中, 然後pass給main()方法裏的String[] args參數

Properties

以 “.properties”為副檔名的檔案, 可以存放key-value的值供java使用, 如test.properties
hostName=mahaljsp.ddns.net
userName=user
password=pass

載入及使用Porperties File

        Properties properties=new Properties();
        try {
            FileInputStream fis=new FileInputStream("test.properties");
            properties.load(fis);
        } catch (FileNotFoundException ex) {}
        catch (IOException ex) {}
        System.out.println("HostName : "+ properties.getProperty("HostName"));
        System.out.println("UserName : "+ properties.getProperty("UserName"));
        System.out.println("Password : "+ properties.getProperty("Password"));

test.properties要放在根目錄之下, 與manifest.mf同位置

Command Line載入Properties

System.out.println(“Test : “+System.getProperty(“usnername”));
然後於命令列下達 : java -Dusername=Thomas myApp

PrintWriter

PrinterWriter pw=new PrintWriter(System.out, true);
pw.println(“This is some output”);

PrinterWriter實作所有print的方法

printf格式

    System.out.printf("顏色 : %s, 數量 : %d, 單價 : $%3.2f\n", "Blue", 10, 10.5);
    System.out.format("顏色 : %s, 數量 : %d, 單價 : $%3.2f\n", "Blue", 10, 10.5);
    String out=String.format("顏色 : %s, 數量 : %d, 單價 : $%3.2f\n", "Blue", 10, 10.5);
    System.out.println(out);
    PrintWriter pw=new PrintWriter(System.out, true);
    pw.printf("顏色 : %s, 數量 : %d, 單價 : $%3.2f\n", "Blue", 10, 10.5);

可以使用格式化的, 有
System.out.printf
System.out.format
String.format

String

String的內容是immutable(永久不變的)

String可使用 + 及concat()結合二字串.
String x=”Java”;
x=x.concat(” OCP”); 新的字串 “Java OCP” 會重新指定給 x
concat()的效能比 “+” 好很多, 且concat()可以一直連續使用
x=x.concat(” OCP”).concat(” 804″);

注意
String x=”Java”;
x.concat(” OCP”).concat(” 804″); x的結果還是 “Java”, 因為並沒有把新的字串指給x

StringBuffer

StringBuffer同String, 但字串相加使用 append, 且字串內容是可以改變的. StringBuffer 是thread-safe, 但效能比String好很多
StringBuffer x=new StringBuffer(“Java”);
x.append(” OCP”).append(” 804″);
x的值會變更為 “Java OCP 804”

StringBuilder

同StringBuffer, 不過是 non-Thread-Safe, 所以效能又比StringBuffer更好

        StringBuilder sb=new StringBuilder();
        sb.append(", 巨匠電腦\n");
        sb.insert(0, "彰化");
        sb.append("[");
        for(int i=0;i<=10;i++){
            sb.append(i).append(" ");
        }
        sb.append("]");
        System.out.println(sb);

String 常用方法

equals(), contains(), replace()

substring(啟始字, 結束字)

substring啟始字由0開始, 結束字由1開始
StringBuilder s=new StringBuilder(“123456789”);
s.substring(0,2);
s還是”0123456789″, 因為substring是會傳回取出的新字串, 而上面並沒有接收新字串

split()方法

        String str="This is a computer";
        String[] array=str.split(" ");
        for(String s:array){
            System.out.println(s);
        }

StringTokenizer(tokenizer標記解析器)

        String str="Blue Shirt, Red Shirt, Black Shirt, Maroon Shirt";
        StringTokenizer st=new StringTokenizer(str, ", ");
        while(st.hasMoreTokens()){
            System.out.println(st.nextToken());
        }

同split()方法, 但分割可以是多個字, 如 “, abc” 表示遇到 “,” 或 a or b or c, 都進行分割, 並需使用iterate存取分割後的結果

Scanner類別

可以解析字串, 並用nextXXX()取出原生資料

        String str="1.11, 2.22, 3.33, 4.44, 5.55";
        Scanner s=new Scanner(str).useDelimiter((", "));
        while(s.hasNextFloat()){
            float f=s.nextFloat();
            System.out.println(f);
        }
    }

useDelimiter(“, “)<==指是是要分割的字串Delimiter[dɪˋlɪmɪtɚ]定義符號

原生資料物件化

–todo start

原生資料不是物件, 所以不能參與物件導向的機制. 所以把原生資料包裝(wrapper)成物件, 就是最佳的解決方式. 包裝後的物件對應的類別如下
char  : Character
byte : Byte
short : Short
int : Integer
long : Long
float : Float
double : Double
boolean : Boolean

字串數字互轉

int x=Integer.parseInt(“100”);
String s=String.valueOf(100);

自動裝箱拆箱

  int i=10;
  Integer o=new Integer(i);
  o=i;//Auto box
  i=0;//Auto unbox

數字池

-128~127的數字會在數字池產生物件,  同字串池

方法重載

尋找接收方法的機制
1. 先尋找能向上轉型的方法-int->long->float->double
2. 啟動自動裝箱拆箱機制
3. 找尋varags的方法

Switch()支援

switch支援byte, char, short, int, String.  而且也支援Enumerated, 只不過是編譯器在switch裏自動加上i.intValue()

–todo end

java.text package

DecimalFormat

可以利用DecimalFormat創造一個物件, 再利用此物件的format()方法接收數字, 傳出想要的數字格式

DecimalFormat的建構子可人接收pattern,
#預告一個數字, 若該位置沒有數值則不顯示
0預告一個數字, 若該位置沒有數值則以 0 顯示

    public class TextTest {
        public static void main(String[] args) {
            DecimalFormat d=new DecimalFormat("000,000,000.00");
            System.out.println("Total : "+ new DecimalFormat("000,000,000.00").format(5000));
        }
    }

DateFormat

DateFormat為抽像類別, 利用三種方法取得物件實体
DateFormat.getDateInstance() : 日期格式
DateFormat.getTimeInstance() : 時間格式
DateFormat.getDateTimeInstance() : 日期時間格式

然後再利用實体的format()方法接收日期時間

    public class TextTest {
        public static void main(String[] args) {
            DateFormat df1=DateFormat.getDateInstance(DateFormat.SHORT, Locale.TAIWAN);
            DateFormat df2=DateFormat.getTimeInstance(DateFormat.FULL, Locale.TAIWAN);
            DateFormat df3=DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.TAIWAN);
            System.out.println(df1.format(new Date()));
            System.out.println(df2.format(new Date()));
            System.out.println(df3.format(new Date()));
        }
    }

DateFormat的日期時間格式有
DateFormat.SHORT
DateFormat.MEDIUM
DateFormat.LONG
DateFormat.FULL

區域物件使用Locate.xxx : 見第15章

df.parse(字串) : 可將字串轉成Date物件

Date

Date的建構子有二種
Date() : 取得目前時間
Date(long) : 自1970/01/01 : 0:0:0 到 long的時間, 單位為毫秒

Date d=new Date();
d.getTime() : 取得目前時間(毫秒數)
d.setTime(1000*2*86400+d.getTime());設定為二天後的時間

正規表示法(Regular Expressions)

正規表示法, 是用來搜尋字串的樣式, 很不好記, 但又很愛考, 所以很頭大

Pattern正規樣式

. 任意一個字元
* 任意多個字元, 包含0
+ 任意多個字元, 不包含0
? 任意0個或1個字元
範圍
| 分隔樣式
^ 一行的開頭
$ 一行的結尾
\b 開始或結尾的字串
 \B 不是開頭或結尾 的字串
[] 在[]中的任意一個字元
[^] 不在[]中的任意一個字元
{n} 包含前面n個字元
{n,} 包含前面n個字元以上
{n,m} 包含前面n個字元以上, m個以下

 

Pattern 結果
ABC. ABCD  ABC2  ….
A.B ACB AZB
A*B ACB AXYB
ABC[XYZ] ABCX ABCY ABCZ
ABC[A-F] ABCA ABCB ABCC ABCD ABCE ABCF
ABC[A|ABC|1234] ABCA ABCABC ABC1234
ABC[A-F]{2,3} ABCEF ABCACD

Pattern類別

先使用Pattern.compile(String) 產生一個要過濾的物件p, 再使用物件p.matches(String), p.find(String), p.lookingAt(String)產生Matcher的物件

    public class PatternTest {
        public static void main(String[] args) {
            Pattern p=Pattern.compile("".*WAS.*", Pattern.CASE_INSENSITIVE");
            Matcher m=p.matcher("I was been there before");
            System.out.println(m.matches());
        }
    }

Pattern.compile()第一個參數即為模版, 上述的 “.*” 是指任意多個字元,  不可以只寫 “*”第二個參數為比對旗標, 有
CANNOT_EQ: 完全正規化相等模式
CASE_INSENSITIVE : 忽略大小寫

p.matcher(String)即把要過濾的原字串傳入, 然後產生Matcher的物件 m. m有三個方法傳回比對的結果
m.matches() : 必需整個字串完全符合過濾模板 : 傳回true/false
m.find() : 從上一次比較結束的地方開始, 與模板比對, 有找到傳回true, 否則傳回false. 找到後, 可從m.start()及m.end()取得開始及結束的位置
m.lookingAt() :

m.replaceAll(“is”), 會先使用find的方式找到模版的字, 再將之取代掉

    String t="It was the best of times";
    Pattern p1=Pattern.compile("w.s");
    Matcher m1=p1.matcher((t));
    if(m1.find()){
        System.out.println(m1.group());
    }

m1.group() 結果為 “was”

 String t="Longlonglong ago, in a galaxy far far away";
    Pattern p1=Pattern.compile("ago.*");
    Pattern p2=Pattern.compile("gal.{6}");
    Pattern p3=Pattern.compile("(long){2}");
    Matcher m;
    m=p1.matcher((t));
    if(m.find())System.out.println(m.group());
    m=p2.matcher((t));
    if(m.find())System.out.println(m.group());
    m=p3.matcher((t));
    if(m.find())System.out.println(m.group());

    結果為
    ago, in a galaxy far far away
    galaxy fa
    longlong

貪婪的截取

    Pattern p4=Pattern.compile("ago.*far");
    m=p4.matcher((t));
    if(m.find())System.out.println(m.group());        
    Pattern p5=Pattern.compile("ago.*?far");
    m=p5.matcher((t));
    if(m.find())System.out.println(m.group());

    結果 :
    ago, in a galaxy far far
    ago, in a galaxy far

正規取法, 會一直截取下去, 直到最後, 或者最後一個字串為止

 String t="it was the best of times or it was the worst of times";
    Pattern p1=Pattern.compile("^it.*?times");
    Pattern p2=Pattern.compile("\\sit.*times$");
    Pattern p3=Pattern.compile("\\bor\\b.{3}");
    Matcher m;
    m=p1.matcher((t));
    if(m.find())System.out.println(m.group());
    m=p2.matcher((t));
    if(m.find())System.out.println(m.group());
    m=p3.matcher((t));
    if(m.find())System.out.println(m.group());

    結果 : 
    it was the best of times
    it was the worst of times
    or it

Pattern物件的split()方法

先使用Pattern.compile()傳入切割字元, 再用p.split()傳入要切割的字串, 第二個參數是指要切割幾次的意思

    public class PatternTest {
        public static void main(String[] args) {
            Pattern p=Pattern.compile("[:/.]+");
            String[] s=p.split("http://mahaljsp.ddns.net",3);
            for (String str:s){
                System.out.println(str);
            }
        }
    }

String也有split(), 其實是調用Pattern的split()

預定義字元類別(Predefined Character class)

\d : 表示[0-9]
\w : 表示[a-2A-Z0-9]
\s : 表示 空白, 包含 \r \t \n \f \0XB
如下例
\\d\\d包含2個數字
\\sin\\s : in的前後都是空白
\\Sin\\S : in的前後都不是空白

    String t="It was the best of times 50 20";
    Pattern p1=Pattern.compile("\\d\\d");
    Matcher m1=p1.matcher((t));
    while(m1.find()){
        System.out.println(m1.group());
    }

以上會顯示 50 20

Formatter格式化輸出工具

    public static void main(String[] args) {
        Formatter f=new Formatter(System.out);
        f.format("PI = %f", Math.PI);
    }

 先建立Formatter物件, 建構子可以是輸出地點, 如StringBuffer(可以append的), 檔案, OutputStream

再用format()方法將之輸出

System.out.printf()及使用了Formatter的方式來列印
System.out.format()同printf();

Scanner

簡易的I/O工具
Scanner sc=new Scanner(System.in); //自鍵盤輸入一字串
int i=sc.nextInt(); //輸入數字
String str=sc.next(); //輸入字串

Scanner sc=new Scanner(“Java,Hello”);//自字串取得資料
sc.useDelimiter(“,”);//分隔符號
sc.next(); //取出 “Java”

Scanner sc=new Scanner(new File(“d:/test.txt”); //自檔案取得資料
sc.useDelimiter(“,|#”);//設定分隔符號

各種字串類別效能分析

使用String的 “+”, concat, 及StringBuffer, StringBuilder各相加10萬次, 效能比較如下

    public static void main(String[] args) {
        String s="";
        long t1, t2;
        t1=System.currentTimeMillis();
        for (int i=0;i<100000;i++){
            s=s+"a";
        }
        t2=System.currentTimeMillis();
        System.out.printf("String '+'    運作10萬次共廢時 : %d毫秒\n", t2-t1);

        s="";
        t1=System.currentTimeMillis();
        for (int i=0;i<100000;i++){
            s=s.concat("a");
        }
        t2=System.currentTimeMillis();
        System.out.printf("String concat 運作10萬次共廢時 : %d毫秒\n", t2-t1);
        StringBuffer sb=new StringBuffer();
        t1=System.currentTimeMillis();
        for(int i=0;i<100000;i++){
            sb.append("a");
        }
        t2=System.currentTimeMillis();
        System.out.printf("StringBuffer  運作10萬次共廢時 : %d毫秒\n", t2-t1);
        
        StringBuilder sbd=new StringBuilder();
        t1=System.currentTimeMillis();
        for(int i=0;i<100000;i++){
            sbd.append("a");
        }
        t2=System.currentTimeMillis();
        System.out.printf("StringBuilder 運作10萬次共廢時 : %d毫秒\n", t2-t1);        
    }

 結果如下

String '+'    運作10萬次共廢時 : 4288毫秒
String concat 運作10萬次共廢時 : 1100毫秒
StringBuffer  運作10萬次共廢時 : 3毫秒
StringBuilder 運作10萬次共廢時 : 2毫秒

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *