java编程思想--13字符串

一、字符串的特点
        String是一个特殊的对象,之所以是对象,这是为了方便对字符串进行各种操作。同时String类具有final属性,所以String类不能被继承,其方法也不能被覆写。将字符串赋值给标识符时,是把字符串对象的地址赋给了引用变量。
        字符串一旦被初始化成功,就是一个常量,不能被改变,若对字符串进行修改操作,实际上是建立了新字符串对象。
形如:
        String s =  new String("abc");
        看似只建立了一个字符串对象,其实是两个,"abc"是一个,将其作为参数传入构造函数得到的新字符串又是一个,因此这种新建字符串的方法不太好,直接这样就可以了:
                String s = "abc";
        String类复写了Object中的equals方法,用于比较两字符串是否相同。
                s1 = "abc";
                s2 = "abc";
                s1.equals(s2);//结果为true
        另一种比较:
                boolean a = (s1 == s2);//结果为true
        在常量池中已经存在的字符串不会再新建对象,因此s1与s2指向同一个对象。

二、字符串常见操作:
1.获取
        获取字符串长度
                int length();
        根据位置获取某个字符  
                char charAt(int index);
        获取该字符在字符串中的位置,接收的是该字符的ASC码
                int indexOf(int ch);//返回该字符在字符串中第一次出现的位置
                int indexOf(int ch,int fromIndex);//从fromIndex指定位置开始,返回ch在字符串中出现的位置
                int indexOf(String str);//返回给定字符串在字符串中第一次出现的位置
                int indexOf(String str,int fromIndex);//从fromIndex指定位置开始,返回给定字符串在字符串中出现的位置
        以上四种获取位置的方法,如果没有找到,则返回-1
        相反的,如果获取反向索引,即字符或字符串最后一次出现的位置,则使用lastIndexOf方法,参数同上面四个函数
                int lastindexOf(int ch);//返回该字符在字符串中最后一次出现的位置
                int lastindexOf(int ch,int fromIndex);//从fromIndex指定位置开始,返回ch在字符串中最后一次出现的位置
                int lastindexOf(String str);//返回给定字符串在字符串中最后一次出现的位置
                int lastindexOf(String str,int fromIndex);//从fromIndex指定位置开始,返回给定字符串在字符串中最后一次出现的位置
2.判断
        字符串中是否包含有指定子串
                boolean contains(String str);
        需要说明的是,indexOf函数也能判断是否包含有子串,因为若没有找到子串,该函数返回-1,到底用哪个方法视情况而定。
        字符串中是否有内容
                boolean isEmpty();//实际上函数内部判断length()是否返回0,若返回0,则isEmpty()返回true,否则返回false
        字符串是否以指定内容开头
                boolean starsWith(String str);
        字符串是否以指定内容结尾
                boolean endesWith(String str);
        判断字符串是否相同
                boolean equals(String str);
                boolean equalsIgnoreCase(String str);//忽视大小写,判断字符串是否相同
 3.转换
        将字符数组转成字符串
        构造函数
                String(char[]):初始化时就转化
                String(char[],offset,count):将字符数组中的一部分转换成字符串
        静态方法
                static String copyValueOf(char[] ch);
 
static String copyValueOf(char[] data,int offset,int count)
                static String valueOf(char[] ch);
        将字符串转成字符数组  
                char[] toCharArray();
        将字节数组转成字符串
                String(byte[]):初始化时就转化
                String(byte[],offset,count):将字节数组中的一部分转换成字符串
        将字符串转成字节数组 
                byte[] getBytes()
  将基本数据类型转成字符串
                static String valueOf(int)
                static String valueOf(double)
        字符串和字节数组在转换过程中,是可以指定编码表的。
4.替换
        将旧字符替换为新字符
                String replace(oldchar,newchar);
        注意,由于字符串的不可变性,返回的是一个新字符串对象,如果找不到要替换的字符,则返回原串
        用到正则表达式的方法:
                replaceAll(String regex, String replacement) :使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
                replaceFirst(String regex, String replacement) :使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
5.切割
        String[] split(regex reg); 按指定的正则表达式作为分隔符切割字符串
        注意:切割的时候,末尾的末尾的空字符串会全部略去

        获取子串(如果角标不存在,会出现角标越界异常)
                String substring(int begin);按起点获取
                String substring(int begin,int end);按起点-终点获取,注意:包含头不包含尾巴,即参数2,4指的是角标2-3的子串
6.转换大小写,去除空格,比较
        (1)将字符串转换成大写或者小写
                String toUpperCase();
                String toUpperCase();
        (2)将字符串两端的多个空格去掉
                String trim();
        (3)对两个字符串进行自然顺序的比较,注意:自然顺序指的是字符Unicode码的数值大小
                int compareTo(String);
                如果字符串等于参数字符串,则返回值0,如果小于参数字符串则返回负数,如果大于参数字符串则返回正数,具体的返回值为第一个不相等的字符的unicode码的差值。


三、字符串练习
        1,模拟一个trim方法,去除字符串两端的空格。
        思路:
                (1),判断字符串第一个位置是否是空格,如果是继续向下判断,直到不是空格为止。结尾处判断空格也是如此。
                (2),当开始和结尾都判断到不是空格时,就是要获取的字符串。


2,将一个字符串进行反转。将字符串中指定部分进行反转,"abcdefg";abfedcg
        思路:
                (1),曾经学习过对数组的元素进行反转。
                (2),将字符串变成数组,对数组反转。
                (3),将反转后的数组变成字符串。
                (4),只要将或反转的部分的开始和结束位置作为参数传递即可。
class StringTest
{

public static void sop(String str)
{
System.out.println(str);
}
public static void main(String[] args)
{
String s = " ab cd ";

sop("("+s+")");
// s = myTrim(s);
// sop("("+s+")");

sop("("+reverseString(s)+")");

}


//练习二:将字符串反转。
/*
思路:
1,将字符串变成数组。
2,对数组反转。
3,将数组变成字符串。
*/

public static String reverseString(String s,int start,int end)
{
//字符串变数组。
char[] chs = s.toCharArray();

//反转数组。
reverse(chs,start,end);

//将数组变成字符串。
return new String(chs);
}
public static String reverseString(String s)
{
return reverseString(s,0,s.length());

}

private static void reverse(char[] arr,int x,int y)
{
for(int start=x,end=y-1; start {
swap(arr,start,end);
}
}
private static void swap(char[] arr,int x,int y)
{
char temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}

//练习一,去除字符串两端空格。
public static String myTrim(String str)
{
int start = 0,end = str.length()-1;

while(start<=end && str.charAt(start)==' ')
start++;

while(start<=end && str.charAt(end)==' ')
end--;

return str.substring(start,end+1);
}
}

3,获取一个字符串在另一个字符串中出现的次数。
                "abkkcdkkefkkskk"
        思路:
                (1),定义个计数器。
                (2),获取kk第一次出现的位置。
                (3),从第一次出现位置后剩余的字符串中继续获取kk出现的位置。每获取一次就计数一次。
                (4),当获取不到时,计数完成。

class StringTest2
{

/*
练习三。

*/

public static int getSubCount(String str,String key)
{
int count = 0;
int index = 0;

while((index=str.indexOf(key))!=-1)
{
sop("str="+str);
str = str.substring(index+key.length());

count++;
}
return count;
}

/*
练习三,方式二。

*/
public static int getSubCount_2(String str,String key)
{
int count = 0;
int index = 0;

while((index= str.indexOf(key,index))!=-1)
{
sop("index="+index);
index = index + key.length();

count++;
}
return count;
}

public static void main(String[] args)
{
String str = "kkabkkcdkkefkks";

///sop("count====="+str.split("kk").length);不建议使用。

sop("count="+getSubCount_2(str,"kk"));
}

public static void sop(String str)
{
System.out.println(str);
}
}


4,获取两个字符串中最大相同子串。第一个动作:将短的那个串进行长度一次递减的子串打印。
        "abcwerthelloyuiodef"
        "cvhellobnm"
        思路:
                (1),将短的那个子串按照长度递减的方式获取到。
                (2),将每获取到的子串去长串中判断是否包含,如果包含,打印-----已经找到!。
class StringTest3
{
/*
练习四。
*/
public static String getMaxSubString(String s1,String s2)
{

String max = "",min = "";

max = (s1.length()>s2.length())?s1: s2;

min = (max==s1)?s2: s1;

// sop("max="+max+"...min="+min);
for(int x=0; x {
for(int y=0,z=min.length()-x; z!=min.length()+1; y++,z++)
{
String temp = min.substring(y,z);

sop(temp);
if(max.contains(temp))//if(s1.indexOf(temp)!=-1)
return temp;
}
}
return "";
}


public static void main(String[] args)
{
String s1 = "ab";
String s2 = "cvhellobnm";
sop(getMaxSubString(s2,s1));
}

public static void sop(String str)
{
System.out.println(str);
}
}


四、StringBuffer类
        StringBuffer类是字符串缓冲区,是一个容器。
        缓冲区的特点:
                (1).长度是可变化的
                (2).可以字节操作多个数据类型
                (3).最终会通过toString方法变成字符窜
                (4).修改后返回同一个对象,并不新建对象
        什么时候用缓冲区:当数据类型不确定,数据个数也不确定,最后要得到字符串的时候,用缓冲区,比数组方便。

五、StringBuffer的方法
        构造函数:
                 StringBuffer()初始容量为16字符
                 StringBuffer(int capacity)指定初始容量
                 StringBuffer(String str)初始化内容
        方法:
                 1.存储
                         StringBuffer append()函数:支持基本数据类型的添加(除了byte和short),将指定数据作为 添加到已有数据的结尾处
                   如下形式是可行的
                         StringBuffer sb = new StringBuffer();
                         sb.append("abc").append(true).append(34);//方法调用链

                   插入方法
                         StringBuffer insert(index,数据)将数据插入到指定位置,可以传入多种数据类型

                 2.删除
                         StringBuffer delete(int start,int end):删除缓冲区中的数据,包含start,不包含end
                         StringBuffer deleteCharAt():删除指定位置字符
 
                    清空缓冲区
                         sb.delete(0,sb.length());
 
                  3.获取
                         char charAt(int index)获取指定位置的字符
                         int indexOf(String str)获取子串的位置
                         int lastIndexOf(String str)获取子串最后一次出现的位置
                         int length()获取缓冲区长度
                         String substring(int start, int end)截取子串
                  4.修改
                         StringBuffer replace(int start,int end,String str)将指定子串替换掉
                         void setCharAt(int index,char ch)替换指定位置的字符,无返回值
                  5.反转
                         StringBuffer reverse();
                  6.转存到数组
                         void getChars(int srcBegin,int scEnd,char[] dst,int dstBegin)
                        获取缓冲区的指定数据并按字符存入指定数组的指定位置,这类方法都要注意角标越界异常

六、StringBuilder类
         StringBuilder类:JDK1.5增加内容 新缓冲区类
         与StringBuffer的区别:StringBuffer是线程同步,StringBuildr是线程不同步,由于简化同步操作,后者效率更高,开发建议使用后者

七、基本数据类型对象包装类
        1.基本数据类型和它们对应的包装类如下:
                  byte                        Byte
                  short                      Short
                  int                           Integer
                  long                       Long
                  float                       Float
                  double                  Double 
                  char                       Character
                  boolean                Boolean
        将基本数据类型包装后能提供更多的方法,实现更强大的功能。最常见的作用:用于基本数据类型和字符串类型之间做转换。
        基本数据类型转换成字符串:
                基本数据类型+""
                基本数据类型.toString(基本数据类型值)

        字符串转成基本数据类型:
                X a = X.parseX(String):X代表基本数据类型的包装类
               若字符串书写格式不是基本数据,会报数据格式异常

        2.重要的方法
                十进制转换
                        Integer.toBinaryString();转换成二进制
                        Integer.toHexString();转换成十六进制
                        Integer.toOctalString();转换成八进制
  其他进制转换成十进制
                        parseInt(String s,int radix)接收指定进制的数字字符串,转换成十进制
                Integer构造方法
                        Integer(String s)接收数字字符串
                基本数据包装类转换成基本数据类型
                        Integer.intValue();
         3.  1.5版本新特性 基本数据类型自动装箱
                Integer x=4;数值自动装箱变成对象 
                x=x+2;这个语句先进行自动拆箱,变成int类型,加法运算后,再自动装箱
                注意:若x=null,会抛空指针异常
                下面代码:
                       Integer a=128;
                       Integer b=128;
                       System.out.println(a==b);//打印结果为false

                       Integer a=127;
                       Integer b=127;
                       System.out.println(a==b);//打印结果为true

             之所以这样,原因是当数值在byte范围内时,对于新特性,不会开辟新的空间

正则表达式概述

 1)定义:符合一定规则的表达式。
2)作用:用于专门操作字符串。
3)特点:用于一些特定的符号来表示一些代码操作。这样就简化书写。
4)所以学习正则表达式,就是在学习一些特殊符号的使用。
5)好处:可以简化对字符串的复杂操作。
6)弊端:符号定义越多,正则越长,阅读性越差。

二 正则表达式具体操作功能

我将毕老师讲的功能进行了封装,并且进行了具体的总结,便于以后复习哈
/*
正则表达式
具体操作功能
1.匹配 String matches(); 用规则匹配整个字符串,只要有一处不符合规则,就匹配结束,返回false

2.切割 String split();

3.替换 String replaceAll();

4.获取 将字符串中符合规则的子串取出
操作步骤 1)将正则表达式封装成对象
2)让正则对象和要操作的字符串相关联
3)关联后,获取正则匹配引擎
4)通过引擎对符合规则的子串进行操作,比如取出

*/
import java.util.regex.*;//演示获取的时候用到


class RegexDemo
{
public static void main(String[] args)
{
/*
匹配
//demo();
//checkQQ_1();
//checkQQ_2();
//checkTel();
*/
//------------------------------------------------------------------------
/*
切割
splitDemo("zhangsan lisi wangwu"," +");//按多个空格切割
splitDemo("zh.hahha.zizi","\\.");//按.切割
splitDemo("c:\\abc\\a.txt","\\\\");//按\\切割
*/
splitDemo("fauuudadiidadagglop","(.)\\1+");//按叠词切割。为了可以让规则的结果被重用,可以将规则封装成一个组,用()完成。
//组的出现都有编号,从1开始,想要使用已有的组可以通过\n(n就是组的编号)的形式
// 来获取

// ((())(())) 有5个组,几个左括号就有几个组


//------------------------------------------------------------------------

/*
替换
String str = "rerq1321212121afaraqe54254252fsfs";
replaceAllDemo(str,"\\d{5,}","#");//将字符串中的数组替换成#

String str1 = "fauuudadiidadagglop";
replaceAllDemo(str1,"(.)\\1+","&");//将叠词替换成&
replaceAllDemo(str1,"(.)\\1+","$1");//将重叠的字符替换成单个字母(zzz->z)
*/
//------------------------------------------------------------------------


//获取
getDemo();
}


//========================================================================
public static void getDemo()
{
String str = "ming tian jiu yao fang jia le ,da jia";
String reg = "\\b[a-z]{3}\\b";

//将规则封装成对象
Pattern p = Pattern.compile(reg);
//让正则对象和要作用的字符串相关联,获取匹配器对象
Matcher m = p.matcher(str);

//System.out.println(m.matches());//其实String类中的matches方法用的就是Pattern和Matcher对象来完成的
//只不过被String的方法封装后用起来比较简单。但是功能却单一。

/*
//通过引擎对符合规则的子串进行操作
boolean b = m.find();
System.out.println(b);
//用于获取匹配后的结果
System.out.println(m.group());
*/

//通过引擎对符合规则的子串进行操作并获取匹配后的结果
while(m.find())
{
System.out.println(m.group());
//System.out.println(m.start()+"..."+m.end());
}
}

//========================================================================

public static void replaceAllDemo(String str,String reg,String newStr)
{
str = str.replaceAll(reg,newStr);//str已经定义了
System.out.println(str);
/*
String s = str.replaceAll(reg,newStr);
System.out.println(s);
*/
}

//========================================================================

public static void splitDemo(String str,String reg)
{
String[] arr = str.split(reg);
//System.out.println(arr.length);
for(String s : arr)
{
System.out.println(s);
}
}


//========================================================================

public static void demo()
{
String str = "a34";
String reg = "[a-zA-Z]\\d?";

boolean b = str.matches(reg);
System.out.println(b);

}

//需求:匹配手机号码 要求:只有 13xxx 15xxx 18xxx
public static void checkTel()
{
String tel = "19897986987";
String reg = "1[358]\\d{9}";
boolean b = tel.matches(reg);
System.out.println(b);
}

//需求:对QQ号码进行校验, 要求:5~15 0不能开头 只能是数字
public static void checkQQ_2()//使用正则表达式
{
String qq = "1928759832";
String reg = "[1-9]\\d{4,14}";

boolean flag = qq.matches(reg);
if(flag)
System.out.println(qq+"...is ok");
else
System.out.println(qq+"...nono");
}

public static void checkQQ_1()//使用String类中的方法,进行组合完成了需求
{
String qq = "0121212";
int len = qq.length();
if(len>=5 && len<=15)
{
if(!qq.startsWith("0"))
{
try
{
long l = Long.parseLong(qq);
System.out.println("qq:"+qq);
}
catch (NumberFormatException e)
{
System.out.println("出现非法字符.....");
}
/*
char[] arr = qq.toCharArray();//将此字符串转换为一个新的字符数组
boolean flag = true;
for(int x=0;x {
if(!(arr[x]>='0' && arr[x]<='9'))
{
flag = false;
break;
}
}
if(flag)
{
System.out.println("qq:"+qq);
}
else
{
System.out.println("出现非法字符");
}
*/
}
else
{
System.out.println("不可以0开头");
}
}
else
{
System.out.println("长度错误");
}
}
}


三 正则表达式练习

需求都写在了代码里,
import java.util.*;
class RegexTest
{
public static void main(String[] args)
{
//test();
//ipSort();
checkMail();
}


/*
需求:对邮件地址进行校验
*/
public static void checkMail()
{
String mail = "[email protected]";
String reg = "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)+";//相对精确的匹配
reg = "\\w+@\\w+(\\.\\w+)+";//相对不太精确的匹配

//mail.indexOf("@")!=-1;//只要有@就可以


System.out.println(mail.matches(reg));
}


/*
需求:
将下列字符串转成:我要学编程

思路:
到底使用四种功能中的哪一个呢?或者哪几个呢?

1,如果只想知道该字符是对是错,使用匹配
2,想要将已有的字符串变成另一个字符串,使用替换
3,想要按照自己的方式将字符串变成多个字符串,使用切割 获取规则以外的字串
4,想要拿到符合需求的字符串子串,使用获取 获取符合规则的字串

*/

public static void test()
{
String str = "我我我我..要要要..要要....要要学....学学学学....编编编.....编编.编编...程程....程程程";
/*
将已有字符串变成另一个字符串,使用替换

1,可以先将 . 去掉
2,再将多个重复的内容变成单个内容
*/

str = str.replaceAll("\\.+","");
System.out.println(str);
str = str.replaceAll("(.)\\1+","$1");
System.out.println(str);
}


/*
需求
已知ip地址 192.68.1.254 102.29.39.234 10.10.10.10 2.2.2.2 8.109.09.30
将ip地址进行地址段顺序的排序

思路
还按照字符串自然顺序,只要让它们每一段都是3位即可
1,按照每一段需要的最多的0进行补齐,那么每一段就会至少保证有3位
2,将每一段只保留3位,这样,所有的ip地址都是每一段3位

*/
public static void ipSort()
{
String ip = "192.68.1.254 102.29.39.234 10.10.10.10 2.2.2.2 8.109.09.30";
ip = ip.replaceAll("(\\d+)","00$1");
System.out.println(ip);

ip = ip.replaceAll("0*(\\d{3})","$1");
System.out.println(ip);

String[] arr = ip.split(" +");

TreeSet ts = new TreeSet();

for(String s : arr)
{
ts.add(s);
}
for(String s : ts)
{
System.out.println(s.replaceAll("0*(\\d+)","$1"));
}
}
}


四 网页爬虫

这个网页爬虫可不是一般的虫子,以后开发会用到
//网页爬虫
import java.io.*;
import java.util.regex.*;
import java.net.*;
class RegexTest2
{
public static void main(String[] args) throws Exception
{
//getMails();
getMails_1();
}

/*
获取网页中的邮件地址
*/
public static void getMails_1() throws Exception
{
URL url = new URL("http://127.0.0.1:8080/myweb/mail.html");

URLConnection conn = url.openConnection();

BufferedReader bufr =
new BufferedReader(new InputStreamReader(conn.getInputStream());

String line = null;

String reg = "\\w+@\\w+(\\.\\w+)+";
Pattern p = Pattern.compile(reg);

while((line=bufr.readLine())!=null)
{
Matcher m = p.matcher(line);
while(m.find())
{
System.out.println(m.group());
}
}
}


/*
获取指定文档中的邮件地址 使用获取功能
*/
public static void getMails() throws Exception
{

//关联文件
BufferedReader bufr =
new BufferedReader(new FileReader("mail.txt"));

String line = null;

//定义规则
String reg = "\\w+@\\w+(\\.\\w+)+";

//将规则封装成对象
Pattern p = Pattern.compile(reg);


while((line=bufr.readLine())!=null)
{
//让正则对象和要作用的字符串相关联,获取匹配器对象
Matcher m = p.matcher(line);

//通过引擎对符合规则的子串进行操作并获取匹配后的结果
while(m.find())
{
System.out.println(m.group());
}
}

}
}


知识点:java.util.regex
一、正则概述
二、Pattern类和Matcher类
三、常用功能
四、案例
--------------------------------------------------------------------------------------------------------
一、正则概述:就是符合一定规则的字符串。
1、特点:将对字符串操作的代码用一些符号来表示;只要使用了指定符号,
就可以调用底层的代码对字符串进行操作。符号的出现,简化了代码的书写。
2、好处:正则的出现,对字符串的复杂操作变得更为简单,代码少。
3、弊端:正则的出现虽然简化了书写,但是却降低了阅读性。
二、Pattern类和Matcher类
  1、Pattern类
       (1)Pattern类:正则表达式的编译表示形式。正则表达式对象的描述类。
(2)常用方法(Pattern类没有构造方法):
        A:public staticPattern compile(String regex):将给定的正则表达式编译到模式中
B:public String pattern( ):返回在其中编译过此模式的正则表达式。
C:public Matcher matcher(CharSequence input):创建匹配给定输入与此模式的匹配器。
D:public static boolean matches(String regex,CharSequence input):
编译给定正则表达式并尝试将给定输入与其匹配。
       (3)常用规则字符:
              A:字符
                     x     字符x(任意字符代表自己本身)
                     \\     反斜线字符
                     \r     回车
                     \n    换行
              B:字符类
                     [abc]       a、b或 c,任意字符一次。
                     [^abc]     任何字符,除了 a、b 或c
                     [a-zA-Z]  a到z或 A到Z,两头的字母包括在内
                     [0-9]             任意的数字字符一次 
              C:预定义字符类
                     .      圆点代表任意的字符
                     \d    数字:[0-9]
                     \w    单词字符:[a-zA-Z_0-9]
                            ( 单词字符:英文,数字,及_ )
              D:边界匹配器
                     ^     行的开头
                     $     行的结尾
                     \b    单词边界(也就是说这里出现的不能是单词字符)
              E:Greedy数量词
                     x?      X一次或一次也没有
                     x*      X零次或多次
                     x+     X一次或多次
                     x{n}         X恰好 n 次
                     x{n,}  X至少n 次
                     x{n,m} X至少n次,但是不超过m次
              F:组
                     捕获组可以通过从左到右计算其开括号来编号。组零始终代表整个表达式。
                     ((A)(B(C)))
                     第一组:(A)(B(C))
                     第二组:A
                     第三组:B(C)
                     第四组:C
              G:叠词的规则(相同的字符重复的出现2次以上):(.)\\1+                     
                        叠词解读: 右边出现的和左边的是一模一样.
                            (.)---代表任意字符的组
                             \\---代表1条反斜线,引用字符
                             1 ---代表(.)的第1组,它只有1个组,所以左右就相同了
                             + ---代表第1组出现1次或者多次  
               注意:在程序中,表达式 \\ 与单个反斜线匹配,而 \{ 与左括号匹配
                            表达式 \\\\ 与 双反斜线匹配.
2、Matcher类
              (1)Matcher类:通过解释 Pattern 对 character sequence 执行匹配操作的引擎。
              (2)常用方法(Matcher类没有构造方法):
A:publicMatcher matcher(CharSequence input):创建匹配给定输入与此模式的匹配器。
B:publicboolean matches( )尝试将整个区域与模式匹配,整个匹配则返回true
C:publicboolean lookingAt( ):
尝试将从区域开头开始的输入序列与该模式匹配,找到匹配则返回true
D:publicboolean find( ):
尝试查找与该模式匹配的输入序列的下一个子序列,存在则返回true
               E:public String group( ):返回由以前匹配操作所匹配的输入子序列。
三、常用功能:
              1、判断功能(String类):public boolean matches(String regex)
              2、切割功能(String类):public String[] split(String regex):返回的是字符数组
              3、替换功能(String类):public String replaceAll(Stringregex,String replacement)
                                                 用给定的字符串去替换字符串对象中满足正则表达式的字符。
              4、获取功能: 使用模式对象Pattern和匹配器对象Mathcher
                     步骤:(1)把正则表达式编译成模式对象
                             (2)通过模式对象调用匹配方法获取到匹配器对象
(3)判断是否存在有满足条件的子串
(4)获取子串
                                   Pattern p = Pattern.compile("a*b");
                                   Matcher m = p.matcher("aaaaab");
                                   boolean b = m. find();
                                   String s = m.group
四、案例
              1、校验(判断)
(1)校验qq号码。需求:键盘录入,必须是5-15位数字;0不能开头                 
import java.util.Scanner;
public class RegexDemo {
public static void main(String[] args){
//用正则表达式
String regex = "[1-9]\\d{4,14}";
// 封装键盘录入
Scanner sc = new Scanner(System.in);
System.out.println("请输入QQ号码:");
String qq = sc.nextLine();
//判断
boolean flag = qq.matches(regex);
System.out.println(flag);
}
}
              (2)校验手机号机:
需求: 第1位是1,第二位可以是数字3458其中之一,后面4位任意数字,
最后5位为任意相同的数字。 例如:18601088888、13912366666                        
importjava.util.Scanner;
public class RegexDemo {
publicstatic void main(String[] args) {
//正则表达式
String regex = "1[3458]\\d{4}(\\d)\\1{4}";
//键盘录入
Scanner sc =new Scanner(System.in);
System.out.println("请输入你的手机号:");
String phone = sc.nextLine();
//判断
boolean flag = phone.matches(regex);
System.out.println(flag);
}
}
              2、叠词切割
                     需求:把字符串中重复出现的字符都去掉
                            叠词:相同的字符重复的出现2次以上。叠词的规则:(.)\\1+                  
public class RegexDemo {
public static void main(String[] args){
//需切割字符串
String str ="sdqqfgkkkhjppppkl";
//正则:右边出现的和左边的是一模一样
String regex ="(.)\\1+";
//有多个叠词,判断并遍历
String[] strArray =str.split(regex);
for (String s :strArray) {
// sd,fg,hj,kl
System.out.println(s);
}
}
}
              3、叠词替换
                 需求:“我我....我...我.要...要要...要学....学学学..学.编..编编.编.程.程.程..程”
                        
将字符串还原成:“我要学编程”。             
                   思路:(1)把点去掉
                          
(2)叠词保留一个                          
public class RegexTest {
public static void main(String[] args){
String str = "我我....我...我.要...要要...要学....
学学学..学.编..编编.编.程.程.程..程";
// 替换,用空字符替换点.
String result =str.replaceAll("\\.","");
//叠词,用一个字替换叠词;$1为保留组1
String finalResult =result.replaceAll("(.)\\1+","$1");
System.out.println(finalResult);
}
}
              4、获取子串          
                   需求:从字符串中,获取3个字符组成的单词(子串)                           
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args){
//定义规则,获取3个字符组成的单词;\\b为边界符号
String regex ="\\b[a-z]{3}\\b";
String str = "fatherand mother i love you";
// 把正则表达式编译成模式对象
Pattern p =Pattern.compile(regex);
// 通过模式对象调用匹配方法获取到匹配器对象
Matcher m =p.matcher(str);
//判断并获取子串,
while(m.find()){
System.out.println(m.group());
}
}
}
               5、获取邮箱
需求:从文本文件或网站上,获取邮箱地址,并遍历出来。
正则表达式解读:单词字符@单词字符2~8位.单词字符2~3位)
String regex = "\\w+@\\w{2,8}(\\.\\w{2,3})+";
                                   ("[a-zA-Z_0-9]+@[a-zA-Z_0-9]{2,8}(\\.[a-zA-Z_0-9]{2,3})+")
                            注意:数量词{2,8}和{2,3},可以不加限制
                     思路:(1)通过字符输入流读取数据。(通过URL连接网站,获取输入流)
                               (2)把读取到的每一行数据进行查找。
                               (3)把查找到的数据存储到集合中。(或直接输出)
                               (4)遍历集合。
                     (A)文本文件中的邮箱   
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args)throws IOException {
// 通过字符输入流读取数据。
BufferedReader br =new BufferedReader(new FileReader("c:\\mail.txt"));
// 创建一个集合
ArrayListarray = new ArrayList();
// 定义邮箱规则
String regex ="\\w+@\\w{2,8}(\\.\\w{2,3})+";
String line = null;
//读取数据,判断并获取满足条件的子串
while ((line = br.readLine()) != null){
Pattern p =Pattern.compile(regex);
Matcher m =p.matcher(line);
while (m.find()){
array.add(m.group());
}
}
br.close();
// 遍历集合。
for (String s :array) {
System.out.println(s);
}
}
}
             
(B)互联网中的邮箱
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CatchEmail {
public static void main(String[] args) throwsException{
//获取URL统一资源定位符
URL url = new URL("http://localhost:8080/email/mail.html");
//开启连接,返回的是连接对象
URLConnection connect =url.openConnection();
//通过连接对象,获取输入字节流
BufferedReader bfr = new BufferedReader(
new InputStreamReader(connect.getInputStream()))
Pattern p = Pattern.compile("\\w+@\\w{2,8}(\\.\\w{2,3})+";);
//读取数据,进行匹配
Stringline = null;
while((line = bfr.readLine())!=null){
Matcher m =p.matcher(line);
while(m.find()){
System.out.println(m.group());
}
}
bfr.close();
}
}


String类
一、概述
        String是字符串的类类型,用于描述字符串事物。字符串是一个特殊的对象。特殊之处就在于:
        Stings= new String();和String s1=””;两种写法都是在创建对象,使用起来一样。
二、从根本上认识java.lang.String类和String池
  首先,我建议先看看String类的源码实现,这是从本质上认识String类的根本出发点。从中可以看到:
  1、String类是final的,不可被继承。public final class String。
  2、String类是的本质是字符数组char[], 并且其值不可改变。private final char value[];
  然后打开String类的API文档,可以发现:
  3、String类对象有个特殊的创建的方式,就是直接指定比如String x = "abc","abc"就表示一个字符串对象。而x是"abc"对象的地址,也叫
  做"abc"对象的引用。
  4、String对象可以通过“+”串联。串联后会生成新的字符串。也可以通过concat()来串联,这个后面会讲述。
  6、Java运行时会维护一个String Pool(String池),JavaDoc翻译很模糊“字符串缓冲区”。String池用来存放运行时中产生的各种字符串,
  并且池中的字符串的内容不重复。而一般对象不存在这个缓冲池,并且创建的对象仅仅存在于方法的堆栈区。
  5、创建字符串的方式很多,归纳起来有三类:
  其一,使用new关键字创建字符串,比如String s1 = new String("abc");
  其二,直接指定。比如String s2 = "abc";
  其三,使用串联生成新的字符串。比如String s3 = "ab" + "c"; 
三、String对象的创建
  String对象的创建也很讲究,关键是要明白其原理。
  原理1:当使用任何方式来创建一个字符串对象s时,Java运行时(运行中JVM)会拿着这个X在String池中找是否存在内容相同的字符串对象,
  如果不存在,则在池中创建一个字符串s,否则,不在池中添加。
  原理2:Java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象。
  原理3:使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢
  了!但绝不会在堆栈区再去创建该String对象。
  原理4:使用包含变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区创建一个String对象。
  另外,String的intern()方法是一个本地方法,定义为public native String intern(); intern()方法的价值在于让开发者能将注意力集中到
  String池上。当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池
  中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。
四、不可变类
  不可改变的字符串具有一个很大的优点:编译器可以把字符串设置为共享。 
  不可变类String有一个重要的优点-它们不会被共享引用。
  是这样的,JAVA为了提高效率,所以对于String类型进行了特别的处理---为string类型提供了串池 
  定义一个string类型的变量有两种方式: 
  string name= "tom "; 
  string name =new string( "tom ") 
  使用第一种方式的时候,就使用了串池, 
  使用第二中方式的时候,就是一种普通的声明对象的方式 
  如果你使用了第一种方式,那么当你在声明一个内容也是 "tom "的string时,它将使用串池里原来的那个内存,而不会重新分配内存,也就是说,string saname= "tom ",将会指向同一块内存 
  另外关于string类型是不可改变的问题: 
  string类型是不可改变的,也就是说,当你想改变一个string对象的时候,比如name= "madding " 
  那么虚拟机不会改变原来的对象,而是生成一个新的string对象,然后让name去指向它,如果原来的那个 "tom "没有任何对象去引用它,虚拟机的垃圾回收机制将接收它。 
五、特点
        字符串最大的特点就是:一旦被初始化就不可以被改变。
例:
        String s1=“abc”;
        String s2 = new String(“abc”);
        String s3=“abc”;
比较的结果:
        s1==s2   ( false )
        s1.equals(s2) ( true )
        //String类复写了Object类中的equals方法,该方法用于判断字符串是否相同。
        s1==s3   ( true )  
        //因为“abc”这个字符串对象已经在内存中存在,作为字符串这种特殊的对象,这种在常量池中存在的数据。s3进行初始化时,发现abc已经在内存中存在,就不会再独立开辟空间,因为再开辟空间就比较浪费空间。因此为了节约内存,在字符串对象当中只要字符串相同,那么s1和s3就指向同一个对象。
s1和s2的区别:
        s1在内存中有一个对象。
        s2在内存中有两个对象。            
 
六、常见操作方法
1、获取
        1.1字符串中包含的字符数,也就是字符串的长度
               int   length()://获取长度。
        1.2根据位置获取位置上的某个字符
               char  charAt(int  index)://当访问到字符串中不存在的角标时,会发生字符串角标越界的错误。
        1.3根据字符获取该字符存在字符串的位置
              int  indexOf(int ch)://返回的是ch在字符串中第一次出现的位置。//传入的是字符对应的ASCII码。//如果没有找到,返回-1。
              int  indexOf(int ch,int fromIndex)://从fromIndex指定位置开始,获取ch在字符串中出现的位置。
              int  indexOf(String str)://返回的是str在字符串中第一次出现的位置。
              int  indexOf(String str,int fromIndex)://从fromIndex指定位置开始,获取str在字符串中出现的位置。
              int  lastIndexOf()://反向索引 
2、判断
        2.1字符串中是否包含某一个子串
              booleancontains(str);
        //特殊之处:indexOf(str)可以索引str第一次出现的位置,如果返回-1表示该str不在字符串中存在。所以,也可以用于对指定判断是否包含。如:if(str.indexOf(“aa”)!=-1)而且该方法既可以判断,又可以获取出现的位置。如果只为判断,用contains。
        2.2字符串中是否有内容
              booleanifEmpty();//原理就是判断长度是否为0。
        2.3字符串是否是以指定内容开头
              booleanstartsWith(str);
        2.4字符串是否是以指定内容结尾
              booleanendsWith(str);
        2.5判断字符串内容是否相同,复写了Object类中的equals方法
              booleanequals(str);
        2.6判断内容是否相同,并忽略大小写。
              booleanequalsIgnoreCase();
3、转换
        3.1将字符数组转成字符串
             构造函数:String (char[]);
                                 String(char[],offset,count);//将字符数组中的一部分转成字符串。
             静态方法:
                                 static String copyValueOf(char[]);
                                 staticString copyValueOf(char[] data,int offset ,int count );
                                 static String valueOf(char[]);
        3.2将字符串转成字符数组
              char[]toCharArray();
        3.3将字节数组转成字符串
              String (byte[]);
              String(byte[],offset,count);//将字节数组中的一部分转成字符串。count表示个数。
        3.4将字符串转成字节数组
              byte[]getBytes();
        3.5将基本数据类型转成字符串
              StringvalueOf(int);
              StringvalueOf(double);
        特殊:字符串和字节数组在转换过程中,是可以指定编码表的。
4、替换
        Stringreplace(oldchar,newchar);//返回的是一个新字符串。如果要替换的字符不存在,返回的还是原字符串。
5、切割
        String[] split(regex);//涉及到正则表达式的点,不能作为切割字符串的regex。
6、子串,获取字符串中的一部分
        String substring(begin);//从指定位置开始到结尾。如果角标不存在,会出现字符串角标越界异常。
        Stringsubstring(begin,end);//包含头,不包含尾。
7、转换,去除空格,比较
        7.1将字符串转成大写或小写
              StringtoUpperCase();
              String toLowerCase();
        7.2将字符串两端的多个空格去除
              String trim();        
        7.3对两个字符串进行自然顺序的比较
              intcompareTo(String);

StringBuffer
一、概述
        StringBuffer是一个容器,字符串的组成原理就是通过该类实现的。StringBuffer可以对字符串内容进行增删改查等操作,很多方法和String相同。
二、特点
        1、而且长度是可变化的。(数组是固定的)
        2、可以直接操作多个数据类型。(数组只能操作一个)
        3、最终会通过toString方法变成字符串。
三、常见操作
1、存储
        StringBuffer append():将指定数据作为参数添加到已有数据的结尾处。
        StringBuffer insert(intoffset ,数据):可以将数据插入到指定offset位置。
2、删除
        StringBufferedelete(start,end):删除缓冲区中的数据,包含start,不包含end。
        StringBuffer deleteCharAt(index):删除指定位置的字符。
        清空缓冲区:对象.delete(0,对象.length());
3、获取
        char charAt(int index);
        int indexOf(String str);
        int lastIndexOf(String str);
        int length();
        String substring(int start,int end);
4、修改
        StringBuffer replace(int start,int end,String str);
        void setCharAt(int index,char ch);
5、反转
        StringBuffer reverse();
6、将缓冲区中指定数据存储到指定字符数组中
        voidgetChars(int srcBegin, int srcEnd,char[] dst,int dstBegin)
在JDK1.5版本之后出现了StringBuilder。
        StringBuffer是线程同步的。有锁。效率低
        StringBuilder是线程不同步的。无锁。效率高
以后开发,建议使用StringBuilder。如遇多线程,使用StringBuffer或自己加锁。
升级三因素:
        1、提高效率
        2、简化书写
        3、提高安全性。
基本数据类型包装类 
 
将基本数据类型封装成对象的好处,在于可以在对象中定义更多的功能方法操作该数据。基本数据类型对象包装类的最常见作用,就是用于基本数据类型和字符串类型之间做转换。下面我们来了解包装类的写法形式和常用方法。
一、基本数据类型对象包装类。
        byte               Byte
        short              Short
        int                  Integer
        long               Long
        boolean          Boolean
        float               Float
        double           Double
        char               Character
 
二、基本数据类型转成字符串
        基本数据类型+" "
        基本数据类型.toString(基本数据类型值);
        如:Integer.toString(34);//将34整数变成"34"。
三、字符串转成基本数据类型。
         xxx a=Xxx.parseXxx(string);//必须传入对应类型的字符串。
        如   inta=Integer.parseInt("123");//静态
        booleanb=Boolean.parseBoolean("true");
        Integeri=new Integer("123");
        intnum=i.intValue();//跟上面的静态方式的结果一样,但这种属于对象调用方式。
注意:
        在使用时,Integer  x = null;上面的代码就会出现NullPointerException。
 
四、十进制转成其他进制。
         toBinaryString();
         toHexString(); 
         toOctalString();
五、其他进制转成十进制。
         parseInt(String,radix);
         如:int a= Intager.parseInt("3c",16);
JDK1.5版本以后出现的新特性。
                         Integer x=new Integer(4);
         等效于:Integer x=4;//自动装箱。
        还可以直接进行运算:x=x+2;//x进行自动拆箱。变成了int类型。和2进行加法运算。再将和进行装箱赋给x。x的拆箱动作等效:x.intValue()。
 
六、示例
        Integer x=128;
        Integer y=128;
        x==y   (false)
        Integer m=127;
        Integer n=127;
        m==n ( true)
原因:
        因为m和n指向了同一个Integer对象。因为当数值在byte范围内,对于新特性,如果该数组已经存在,则不会再开辟新的空间。

说明:在下表中,为了方便书写,方法的参数省略,参数的详细信息参考Java API。
获取信息操作 字符串长度 length() 比较字符串引用 “==” 比较字符串内容 equals() 或 compareTo() 已知位置,找字符 charAt() 已知字符(串),找位置 indexOf() 或 lastIndexOf() 判断开头和结尾 startWith() 或 endWith() 其他类型转换为字符串 valueOf() 更改操作 连接字符串 “+” 或者 concat() 替换子字符串 replace() 获取子字符串 subString() 分割字符串 split() 更换大小写 toUpperCase()、toLowerCase() 去除空白符 trim() String是常量,我们常称其为不可变性,意思是一旦创建就不能更改。
所以对于上面的“更改操作”,返回值都是 字符串,但并不是对源字符串进行更改,而是返回了新的字符串。下面有测试代码。
小实验:如果查看Java API文档中对String的方法的说明,会发现用了很多的“return a new String ”。
2. 验证String的不可变性 所谓String的不可变性,是说一旦字符串被创建,对其所做的任何修改都会生成新的字符串对象。
代码如下:
[java] view plaincopyprint?
public static void main(String[] args) { String a = 'abc'; String b = a.toUpperCase(); System.out.println('a: ' + a); System.out.println('b: ' + b); System.out.println('a==b: '+ (a==b)); //当a不发生变化时,不返回新字符串。 String c = a.toLowerCase(); System.out.println('c: ' + c); System.out.println('a==c: '+ (a==c)); }
public static voidmain(String[] args) { String a = 'abc'; String b = a.toUpperCase(); System.out.println('a: ' + a); System.out.println('b: ' + b); System.out.println('a==b: '+ (a==b)); //当a不发生变化时,不返回新字符串。 String c = a.toLowerCase(); System.out.println('c: ' + c); System.out.println('a==c: '+ (a==c)); } 运行结果:
[java] view plaincopyprint?
a: abc b: ABC a==b: false c: abc a==c: true
a: abc b: ABC a==b: false c: abc a==c: true 运行结果分析:
字符串a指向'abc',全为小写;字符串b由a得来,指向'ABC';这时a的内容并没有变化,也就证明了Java中String的不变性。
后面利用'a==b'来判断a,b是否指向同一个对象,返回值为false,也能证明String的不变性。
对于字符串c的例子说明如果a没有发生变化,那么不返回也不需要返回新字符串,所以'a==c'的返回值为true

1)格式化输出
确实,说到C的printf,是不能用重载的+操作符的。
printf("%d %f", x , y);
%d这些为格式修饰符,%d表示整数,x插入到%d的位置,%f表示浮点数,y查到%f的位置。
Java也模仿了C:
public class TestString {
public static void main(String[] args) {
int x = 1;
float y = 1.223f;
System.out.printf("%d %f",x,y);
System.out.println();
System.out.format("%d %f",x,y);
}
}

可以用Formatter在控制台完美的控制间隔,不用你自己去数几个空格了。
public class TestString {
public static void main(String[] args) {
Formatter fm = new Formatter(System.out);
fm.format("%-5s %5s %10s ", "Name","Age","School");
}
}
%数字+s这样的表达像c,位置可以移动。

System.out.println(String.format("%h", 17));
 fm.format("%h", 17);
16进制的格式化输出。

2)正则表达式(regex :regular expression)
字符串处理,文件批处理中经常使用到,很好用,也是容易忘。这个点结合网上的一些知识点来写。
-? 一个可能带有负号的数字不包括数字。
\d   表示一位数字,注意其他语言的\\是在正则表达式中是一个反斜杠,而在java中是正要插入正则表达式的\。

举一反三,那么\d在java中就是\\d了,真正想插入一条反斜杠就要\\\。
String的匹配 利用String的match方法

public class TestString {
public static void main(String[] args) {
System.out.println("-3444".matches("-?\\d+"));
System.out.println("-3".matches("-?\\d"));
System.out.println("-3".matches("(-|\\+)?\\d"));
}
}

result:都是ture

(-|\\+)? 这个比较复杂,|是或的意思,\\+,由于加号有特殊含义,那么要\\转义,所以就是有加号或者负号的其中一个,或者都没有。

split方法:
经常使用的时候是根据空格切割。
String s = Arrays.toString("sdfsdf sf sdf".split(" "));
其实还可以在split参数中输入正则表达式进行切割:
String s = Arrays.toString("sdfsdf sf sdf".split("\\W+"));
String s2 = Arrays.toString("sdfsdf sf sdf".split("n\\W+"));
\w是非单词字符,\w为单词字符,n\\W+ 字母n后跟着一个或多个非中文字符。

参考:
http://blog.csdn.net/kdnuggets/article/details/2526588
和JDK的Pattern类:

Construct Matches
 
Characters
x The character x
\\ The backslash character
\0n The character with octal value 0n (0 <= n <= 7)
\0nn The character with octal value 0nn (0 <= n <= 7)
\0mnn The character with octal value 0mnn (0 <= m <= 3, 0 <= n <= 7)
\xhh The character with hexadecimal value 0xhh
\uhhhh The character with hexadecimal value 0xhhhh
\x{h...h} The character with hexadecimal value 0xh...h (Character.MIN_CODE_POINT  <= 0xh...h <= Character.MAX_CODE_POINT)
\t The tab character ('\u0009')
\n The newline (line feed) character ('\u000A')
\r The carriage-return character ('\u000D')
\f The form-feed character ('\u000C')
\a The alert (bell) character ('\u0007')
\e The escape character ('\u001B')
\cx The control character corresponding to x
 
Character classes
[abc]
a, b, or c (simple class)
[^abc] Any character except a, b, or c (negation)
[a-zA-Z] a through z or A through Z, inclusive (range)
[a-d[m-p]] a through d, or m through p:[a-dm-p] (union)
[a-z&&[def]] d, e, or f (intersection)
[a-z&&[^bc]] a through z, except for b and c: [ad-z] (subtraction)
[a-z&&[^m-p]] a through z, and not m through p: [a-lq-z](subtraction)
 
Predefined character classes
. Any character (may or may not match line terminators)
\d A digit: [0-9]
\D A non-digit: [^0-9]
\s A whitespace character: [ \t\n\x0B\f\r]
\S A non-whitespace character: [^\s]
\w A word character: [a-zA-Z_0-9]
\W A non-word character: [^\w]
 
POSIX character classes (US-ASCII only)
\p{Lower} A lower-case alphabetic character: [a-z]
\p{Upper} An upper-case alphabetic character:[A-Z]
\p{ASCII} All ASCII:[\x00-\x7F]
\p{Alpha} An alphabetic character:[\p{Lower}\p{Upper}]
\p{Digit} A decimal digit: [0-9]
\p{Alnum} An alphanumeric character:[\p{Alpha}\p{Digit}]
\p{Punct} Punctuation: One of !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
\p{Graph} A visible character: [\p{Alnum}\p{Punct}]
\p{Print} A printable character: [\p{Graph}\x20]
\p{Blank} A space or a tab: [ \t]
\p{Cntrl} A control character: [\x00-\x1F\x7F]
\p{XDigit} A hexadecimal digit: [0-9a-fA-F]
\p{Space} A whitespace character: [ \t\n\x0B\f\r]
 
java.lang.Character classes (simple java character type)
\p{javaLowerCase} Equivalent to java.lang.Character.isLowerCase()
\p{javaUpperCase} Equivalent to java.lang.Character.isUpperCase()
\p{javaWhitespace} Equivalent to java.lang.Character.isWhitespace()
\p{javaMirrored} Equivalent to java.lang.Character.isMirrored()
 
Classes for Unicode scripts, blocks, categories and binary properties
\p{IsLatin} A Latin script character (script)
\p{InGreek} A character in the Greek block (block)
\p{Lu} An uppercase letter (category)
\p{IsAlphabetic} An alphabetic character (binary property)
\p{Sc} A currency symbol
\P{InGreek} Any character except one in the Greek block (negation)
[\p{L}&&[^\p{Lu}]]  Any letter except an uppercase letter (subtraction)
 
Boundary matchers
^ The beginning of a line
$ The end of a line
\b A word boundary
\B A non-word boundary
\A The beginning of the input
\G The end of the previous match
\Z The end of the input but for the final terminator, if any
\z The end of the input


量词:吸收文本的方式
Greedy quantifiers            贪婪型
X? X, once or not at all
X* X, zero or more times
X+ X, one or more times
X{n} X, exactly n times
X{n,} X, at least n times
X{n,m} X, at least n but not more than m times
 
Reluctant quantifiers
X?? X, once or not at all
X*? X, zero or more times
X+? X, one or more times
X{n}? X, exactly n times
X{n,}? X, at least n times
X{n,m}? X, at least n but not more than m times
 
Possessive quantifiers
X?+ X, once or not at all
X*+ X, zero or more times
X++ X, one or more times
X{n}+ X, exactly n times
X{n,}+ X, at least n times
X{n,m}+ X, at least n but not more than m times
 
Logical operators
XY X followed by Y
X|Y Either X or Y
(X) X, as a capturing group
 
Back references
\n Whatever the nth capturing group matched
\k Whatever the named-capturing group "name" matched
 
Quotation
\ Nothing, but quotes the following character
\Q Nothing, but quotes all characters until \E
\E Nothing, but ends quoting started by \Q
 
Special constructs (named-capturing and non-capturing)
(?X) X, as a named-capturing group
(?:X) X, as a non-capturing group
(?idmsuxU-idmsuxU)  Nothing, but turns match flags i d m s u x U on - off
(?idmsux-idmsux:X)   X, as a non-capturing group with the given flagsidmsu x on - off
(?=X) X, via zero-width positive lookahead
(?!X) X, via zero-width negative lookahead
(?<=X) X, via zero-width positive lookbehind
(?(?>X) X, as an independent, non-capturing group

3)Pattern和Matcher
public class TestString {
public static void main(String[] args) {
Pattern p = Pattern.compile("\\W+");
Matcher m = p.matcher("qw");
System.out.println(m.matches());
}
}
Pattern.compile,静态方法,Compiles the given regular expression into a pattern。将一个正则表达式编译进Pattern中。
p.mathcer,Creates a matcher that will match the given input against this pattern。创建一个matcher将输入和Pattern匹配。


m.matches,Attempts to match the entire region against the pattern。
boolean,返回匹配结果。

这样就可以传入正则表达式,然后对字符串进行匹配。

1、find和group
public class TestString {
public static void main(String[] args) {
String s = "You're kidding me!";
Pattern p = Pattern.compile("\\w+");
Matcher m = p.matcher(s);
while(m.find()){
System.out.printf(m.group()+" ");
}

int i = 0;
        while(m.find(i)){
            System.out.printf(m.group()+" ");
            i++;
        }
 }
}

result: You re kidding me
You ou u re re e kidding kidding idding dding ding ing ng g me me e


find可以遍历字符串,寻找正则表达式的匹配,group是 Returns the input subsequence matched by the previous match。这样返回的便是第一个匹配多个单词字符 ,所以便是You。find传入参数后,可以调整开始搜索的位置,刚开始为0,那么匹配的是You,i+1之后,匹配到的是ou。

2、end和start
while(m.find()){
System.out.printf(m.group()+" Start:"+m.start()+" End:"+m.end());
}

You Start:0 End:3re Start:4 End:6kidding Start:7 End:14me Start:15 End:17
匹配起始位置的索引,匹配结束位置的索引。

3、split
其实书上讲属性的东西是最简单的,因为文档有,这种文档有的就是自己动手查动手敲代码。Pattern还有两个
String[] split(CharSequence input)
Splits the given input sequence around matches of this pattern.
String[] split(CharSequence input, int limit)
Splits the given input sequence around matches of this pattern.
String string = "kjj~~lkjl~~lkjlJ~~lkj~~";
System.out.println(Arrays.toString(Pattern.compile("~~").split(string)));
System.out.println(Arrays.toString(Pattern.compile("~~").split(string,2)));

result:
[kjj, lkjl, lkjlJ, lkj]
[kjj, lkjl~~lkjlJ~~lkj~~]
(哈哈,作者竟然在书中直接讽刺Sun里面的java设计者,把Pattern的标记设计得难懂。)

4)替换操作
String replaceAll(String regex,String replacement)
Replaces each substring of this string that matches the given regular expression with the given replacement.
String replaceFirst(String regex,String replacement)
Replaces the first substring of this string that matches the givenregular expression with the given replacement.
replaceFirst替换的是第一个匹配的内容。replaceAll是全部替换。

接下来还有比这两者好用的处理方法,加入你要找出abcd字母并且替换成大写字母,如果用上面两种写法的话就要处理多次。
String string = "asdfb sdfoiwer sdfcdf wer sd d sdf cxvxzcv s ef bob b b ";
StringBuffer s2 = new StringBuffer();
Pattern pa = Pattern.compile("[abcd]");
Matcher mc = pa.matcher(string);
System.out.println();
while(mc.find()){
mc.appendReplacement(s2,mc.group().toUpperCase());
}
mc.appendTail(s2);
System.out.println(s2);

result:AsDfB  sDfoiwer  sDfCDf wer sD D sDf  CxvxzCv s ef BoB B   B


mc.find();
mc.appendReplacement(s2,mc.group().toUpperCase());
mc.appendTail(s2);
System.out.println(s2);

result :Asdfb  sdfoiwer  sdfcdf wer sd d sdf  cxvxzcv s ef bob b   b
替换时也能操作字符串,while的时候能够全部替换,如果不用while,只进行一次find操作,那么s2打印出来的只有A,要达到replaceFirst的效果,要用appendTail方法,加尾巴,就是把剩余没替换的补上。这样才会打印完整。

reset方法:
Matcher mc = pa.matcher(string);
每次mc只能match一个字符串,可以用reset方法重新match其他字符串:
mc.reset(String newString);

5)扫描输入
c的输入很简单,有时java经常写Syso(Eclipse的System.out.println的快捷输入,很早之前一位前辈告诉我的,一直受用)。一直输出,却忘了输入怎么写。
可读流对象:
public class TestScanner {
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new StringReader("sdfsdf\nsdfsdf\nsdfsdf"));
try {
System.out.println(br.readLine());
System.out.println(br.readLine());
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}

用Scanner也可以。
Scanner s = new Scanner(System.in);
System.out.println(s.nextLine());
可以在控制台输入后输出。

Scanner定界符:
public class TestScanner {
public static void main(String[] args) {
Scanner s = new Scanner("12, 323, 34, 34, 5");
s.useDelimiter("\\s*,\\s*");
while (s.hasNextInt()) {
System.out.println(s.nextInt());
}
}
}
昨天看到这里的时候卡住了,本来Scanner根据空白字符对输入进行分词:
Scanner s = new Scanner("12 323 34 34 5");
while (s.hasNextInt()) {
System.out.println(s.nextInt());
}
这样可以打印每一个数字。
昨天想了好久的就是定界符这个东西,为什么我用\\d+,\\d+不行,今天再来看想通了,其实定界是作为分隔符来看,\\s是空格,而*是零次或多次,这样说就是以逗号前后无空白或者一个或多个空白,将Scanner里面的内容分隔开。
\\d+,\\d+,以逗号前后有数字作为分隔符,肯定不匹配。为了验证,把s改为W一试,也是可以的。

以前没有Scanner和正则表达式的时候,Java使用的是StringTokenizer,现在基本废弃不用了,当然,IDE还没有提示Deprecated.

String内容就到这里了,输入输出,格式化输出,正则表达式,用好的话,在批处理方面甚是强大,有空补充一下String不变性和内存分配的内容。

----
一、String类
     位于java.lang包中。     
1、概念
         字符串是由许多单个字符连接而成的,它可以由任何字符组成,这些字符必须包含在一对””(双引号)内,这是java语言表示字符串的方法。Java使用java..lang包中的String类来创建字符串对象,因此字符串是一个String类的对象。
2、String类特点
        我们看api文档关于string类的描述:
       1)public final class String
被final修饰,说明字符串类不可以被继承,里面的方法不可以被复写。String类代表字符串,java程序中的所有字符串都作为此类的实例。
String str=”abc”和String str=new string(“abc”)有区别吗?
没有区别。
解读一下String str=“abc”;
Str是一个类类型变量,它指向一个对象,所以abc是一个对象。字符串是一个特殊的对象
  2)   字符串一旦初始化就不可以被改变
  这是它最大的特点。
   解读一个实例
 
 
 
打印kk
这是怎么回事呢?
其实,不是对象变化了,而是字符串类型变量s1改变了,它开始指向“abc”这个对象,现在指向“kk”这个对象。
    String str=“abc”和string str=new string(“abc”)虽然一般情况可以通用,但是还是有区别的。
 
 
   
为什么呢?
==比较不相等是可以理解的,因为不是一个对象。
equals比较的是s1和s2的地址值,原本是object类的方法,而String类复写了object类中的equals方法,定义自己独特的内容,该方法用于判断字符串是否相同。
  s1 和s2有什么区别?面试题
s1在内存中一个对象。
s2在内存中有两个对象。new了一个对象,“abc”又是一个对象。 
 字符串对象在内存中,其实有一个常量池存放的是如“abc”的字符。
比如:创建了一个ab字符串,又创建了一个efg的字符串,如果你又创建了一个abf的字符串,它就在常量池里面分别找a,b,f,拼成abf的字符串。形成对象。
3、String类中常用的方法
      示例:
 
 
原因
S1在内存的常量池中已经存储了一个”abc”,s3再创建对象时,因为字符串是常量,不能被改变,也就没有必要再开辟空间。为节约内存,让S3指向“abc”这个对象即可。
我们学方法区的时候,方法区中都有哪些数据呢?
类的方法,静态数据,还有常量池。
String类是用于描述字符串事物的。那么它就提供了多个方法对字符串进行操作。
   1   获取
    1.1 字符串中的包含的字符数,也就是字符串的长度
          int  length();获取长度
        数组也有长度,但是是数组的属性,不是方法
          字符串的长度是方法。
    1.2 根据位置获取位置上的某个字符
           char charAt(int index)
    1.3 根据字符获取该字符在字符串中的位置
         int   indexOf(int ch )返回时ch在字符串中第一次出现的位置
          往里面传的不是char类型,是int
       因为它接收的是ASCII码
      重载方法
     int indexOf(int ch,int fromIndex)
     返回在此字符串中第一次出现指定字符处的索引,从fromIndex指定的索引开始搜索。
     int indexOf(String str)
     int indexOf(iString str,int fromIndex)
      返回str的位置
  1.4  int lastIndexOf(int ch)反向索引
     演示:
    
 
 注意事项
charAt(int ):当访问到字符串中不存在的脚标时,会发生StringIndexOutOfBoundsException 字符串脚标越界。
IndexOf(int ch):找不到时,就返回-1
  2 判断
   2.1 字符串中是否包含某一个子串 
       boolean contains(CharSequence  s)   CharSequenc是一个接口,子类有一个是string,还有一个是Stringbuffer
     与indexOf(str)相比:indexOf(str)可以索引str第一次出现位置,如果返回-1标识str不存在。所以,也可以用于对指定判断是否包含
        If(str.indexOf(“aa”))!=-1)
        该方法既可以判断,又可以获取位置。
   2.2 字符中是否有内容。
        boolean isEmpty() 原理就是判断长度是否为0,和字符串是否是null有区别
   2.3 字符串是否是以指定内容开头。
        boolean startsWith(String prefix)  
   2.4 字符串是否是以指定内容结尾。
        boolean endsWith(String suffix) 
   2.5 判断字符串的内容是否相同
        boolean equals(str)复写object的方法
   2.6 判断内容是否相同,并忽略大小写
        boolean equalIgnoreCase(str);
   常用:登陆邮箱等
  演示:
  
 
 
 
  3   转换
    3.1 将字符数组转成字符串
         构造函数String(char[])
         构造函数String(char[],offset.count)将字符数组中的一部分转成字符串
         Static String copyValueOf(char[])
         Static string valueOf(char[]) 
    3.2 将字符串转成字符数组
         char[]  toCharArray()  
3.3 将字节数组转成字符串
    IO的时候,要用构造函数String(byte[])
        构造函数String(byte[],offset.count) 
    3.4 将字符串转成字节数组
        byte[] getBytes(Charset charset)     
    3.5 将基本数据类型转换成字符串
        Static String valueOf()参数   int  double 
        例如  3+“”//等价于string.valueOf(3);  
        构造函数
        Static string copyValueOf(StringBuffer sb)
     特殊:
     字符串和字节数组在转换过程中,是可以指定编码表的。
演示:
 
 
4 替换
  String replace(char oldChar, char newChar)  
  String replace(CharSequence target, CharSequence replacement) 
          使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。 
 
演示:
 
 
注意事项:replace():如果要替换的字符不存在,返回的还是原串。被替换后,原串不变,只是将新的对象赋值给String变量而已。
5切割
string[] split(String regex) 
演示:
  
 
 6子串
String substring(int beginIndex) 
String substring(int beginIndex, int endIndex) //包含头,不包含尾
演示:
 
 
 
    7 转换  去除空格  比较
      7.1 将字符串转成大写或者小写  
          String  toUpperCase(Locale locale)  
          String  toLowerCase(Locale locale) 
      7.2 将字符串两段的多个空格去除
          String  trim()  
      7.3 对两个字符串进行自然顺序的比较。
          int compareTo(String anotherString)  
演示:
 
 
 
说明:
   compareTo():如果s1=“acc”,返回2   
     如果小于参数字符串,则返回负数
     如果相等,返回0
     如果大于参数字符串,返回一个大于0的数。
    示例中c>a ,且根据ASCII值,c比a大2.所以返回2
4、字符串练习1
    1) 模拟一个trim方法,去除字符串两端的空格。
       思路:
        1 判断字符串第一个位置是否是空格,如果是,继续向下判断,直到不是空格为止。结尾处判断空格也是如此。
        2 当开始和结尾都判断到不是空格时,就是要获取的字符串。
程序:
 
 
 
2)将一个字符串进行反转,将字符串中指定部分进行反转,”abcdefg”;  abfedcg
   思路:
     1 曾经学习过对数组的元素进行反转。
     2 将字符串变成数组,对数组进行反转。
     3 将反转后的数组变成字符串
     4 只要将或反转的部分的开始和结束位置作为参数传递即可。
Java中,从0数到某个位置的字符串,都是包含头,不包含尾。
程序:
 
 
 
3)获取两个字符串中最大相同子串,第一个动作:将短的那个串进行长度一次递减的子串打印。
“abcwerthelloyuiodef”
  “cvhellobnm”
思路
 1 将短的那个子串按照长度递减的方式获取到
 2 将每获取到的子串去长串中判断是否包含。
   如果包含,已经找到!
程序:
 
 
 
二、StringBuffer类
  1、概念   
 StrinBuffer是一个字符串缓冲区,是一个容器。被final修饰,不可以被继承。
容器的特点就是对数据的改变,字符串的组成原理就是通过该类实现。
StringBuffer可以对字符串内容进行增删,很多方法与string相同。
  2、缓冲区的特点
    1 )StringBuffer是可变长度的。
    2 )可以操作多个数据类型
    3 )最终会通过tostring()方法变成字符串。
 3、常用的方法
    1 )StringBuffer append(Object obj) 将指定数据作为参数添加到已有数据的结尾处。
        StringBuffer insert(int offset, Object obj)在指定位置添加数据
       例如:
    stringBuffer sb=new StringBuffer();
    StringBuffer sb1=sb.append(34);
    System.out.println(sb.toString());//把缓冲区变为字符串
     System.out.println(sb1.toString()); //与上一句结果相同
这就是容器的特点
所以,sb.sppend(“abc”),返回还是本类对象。所以还能调用方法。
可以这么写
Sb.append(“abc”).append(“abc”).append(“abc”).append(“abc”);  方法调用链
结果是abcabcabcabc
    2)StringBuffer delete(int start, int end);删除从start到end位置的数据,包含头,不包含尾
     StringBuffer deleteCharAt(int index) 删除指定位置的字符。
    例如:
Public static void method_del()
{
     StringBuffer sb=new StringBuffer(“abcde”);
    System.out.println(sb.toString());
    Sb.delete(1,3);//返回ade。从第1角标位开始,到第三位,不包括第三位。
      System.out.println(sb.toString());
  Sb.delete(0,sb.length());//清空缓冲区。
}
3 )char charAt(int index) 通过脚标获取字符
    int indexOf(String str) 获取位置
    int lastIndexOf(String str)  
    int length() 获取长度
    String substring(int start)  
    String substring(int start, int end) 记住,返回的是string
 4 )StringBuffer replace(int start, int end, String str) 
 参数:头,尾,被替换的内容
void setCharAt(int index, char ch) 在指定位置替换一个字符 
 注意:返回值是空
 public static void method_update()
{
         StringBuffer sb=new StringBuffer(“abcde”);
   sb.replace(1,4,”java”);//ajavae
  sb.setCharAt(2.’k’);
}
5) StringBuffer reverse() 反转
6) void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)  将缓冲区中的指定数据存储到指定字符数组中。
三、StringBuilder类
   1、概念
    StringBuilder类:线程安全的可变字符序列。在jdk1.5版本以后出现的。一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。
  2、与stringBuffer的不同:
  StringBuffer是线程同步的。StringBuilder是线程不同步,意味着不安全。
  一般使用stringBuilder。如果是单线程,stringBuffer效率低。而stringBuilder快
 所以,多线程建议使用stringBuffer,单线程建议使用stringBuilder。但也可以自己加锁 lock
  小知识:
    Java升级一般有三种原因:1 提高效率2 简化书写3 安全性
而stringBuilder是为提高效率而升级的
四、基本数据类型对象包装类
    按照java面向对象原则,万事万物都是对象。包括基本数据类型。
比如int类型,有自己的取值范围,有多种表现形式等等
怎么把十进制表现为其他进制表现形式呢?只有int类型最清楚
java就把这些基本数据类型全部封装成为对象
五、 基本数据类型对象包装类
  1、基本数据类型对象对应包装类
  基本类型        类类型
  byte类型————Byte  
  short类型————Short
  Int类型————Integer
  long类型———Long
  Boolean————Boolean
  Float——————-Float
  Double————Double
  Char————Character
以Integer为例
属性
static int MAX_VALUE 
          值为 231-1 的常量,它表示 int 类型能够表示的最大值。 
static int MIN_VALUE 
          值为 -231 的常量,它表示 int 类型能够表示的最小值。 
static int SIZE 
          用来以二进制补码形式表示 int 值的比特位数。 
static Class TYPE 
          表示基本类型 int 的 Class 实例。 
  有了对象,我们在程序中就不必自己运算最大值。
基本数据类型对象包装类的最常见作用:就是用于基本数据类型和字符串类型之间做转换。
2、基本数据类型转成字符串
  基本数据类型+””
专业做法
  String    toString(基本数据类型值)  这不是object里面的方法,是integer覆盖的方法
  Static  String toString(int i)  
Integer.toString(34);
3、字符串转成基本数据类型
应用:上网时,在文本框中输入,如果输入年龄24.在文本框中输入的都是字符串,我们需要把字符串的年龄转换为数字。
static int parseInt(String s, int radix)  
1)将一个字符串转为整数
Int num=integer.parseInt(“124”);//必须传入数字格式的字符串。
构造函数也可以完成。
特殊:
2)Boolean 转换
Static boolean parseBoolean(String s)
3)十进制转成其他进制
toBinaryString();
toHexString();
toOctalString();
4)其他进制转成十进制
static int parseInt(String s, int radix) 
parseInt(“110”,2);
4、Jdk1.5版本以后出现的新特性——自动装箱和拆箱
Integer x=4;
x是引用数据类型。右边是一个对象。这叫做自动装箱。
这个升级是为简化书写
还有X=x+2;
x+2  x进行了自动拆箱,变成int类型,和2进行加法运算,再将和进行装箱赋值给x
还有需要注意的是
Integer x=null;可以为空。
所以做运算时,需要判断。
小的新特性
Integer m=128;
Integer m=128;
Integer m=127
Integer n=127;
因为a和b指向了同一个Integer对象。
因为数值在byte范围内,对于新特性,如果该数值已经存在,不会再开辟新的空间。
六、正则表达式
1、概述
  正则表达式是一种描述字符串集的方法,是以字符串集合中各字符串的共有特征为依据的。在程序开发中,正则表达式被广泛地应用在字符串的查找、替换、匹配等情况下,因此灵活地使用正则表达式对程序员来说非常重要。正则表达式中含有一些特殊意义的字符,这些字符称为正则表达式的元字符,例如,“\\d”表示字母0-9中的任何一个,”\d”就是元字符。
  2、常见符号
    说明:X表示字符X或者匹配的规则。
     1)字符
        x                  字符x
        \\                 反斜线字符
        \t                 制表符('\u0009')
        \n                 新行(换行)符('\u000A')
        \r                 回车符('\u000D')
        \f                 换页符('\u000C')
        \a                 报警(bell) 符('\u0007')
   2)字符类
        [abc]                    a、b或c(简单类)
        [^abc]                 任何字符,除了a、b或c(否定)
        [a-zA-Z]               a到z或A 到Z,两头的字母包括在内(范围)
        [a-d[m-p]]            a到d或m 到p:[a-dm-p](并集)
        [a-z&&[def]]               d、e或f(交集)
        [a-z&&[^bc]]        a到z,除了b和c:[ad-z](减去)
        [a-z&&[^m-p]]     a到z,而非m到p:[a-lq-z](减去)
  3)预定义字符类
        .                         任何字符(与行结束符可能匹配也可能不匹配)
        \d                        数字:[0-9]
        \D                       非数字:[^0-9]
        \s                        空白字符:[ \t\n\x0B\f\r]
        \S                       非空白字符:[^\s] 
        \w                       单词字符:[a-zA-Z_0-9]
        \W                      非单词字符:[^\w]
  4)边界匹配器
        ^                         行的开头
        $                         行的结尾
        \b                        单词边界
        \B                       非单词边界
        \A                       输入的开头
        \G                       上一个匹配的结尾
        \Z                       输入的结尾,仅用于最后的结束符(如果有的话)
        \z                        输入的结尾
5)Greedy数量词
        X?                       X,一次或一次也没有
        X*                       X,零次或多次
        X+                       X,一次或多次
        X{n}                    X,恰好n次
        X{n,}                   X,至少n次
        X{n,m}                X,至少n次,但是不超过m 次
6)组和捕获
       捕获组可以通过从左到右计算其开括号来编号。例如,在表达式((A)(B(C)))中,存在四个这样的组:
                    1     ((A)(B(C)))
                    2     \A
                    3     (B(C))
                    4     (C)
       组零始终代表整个表达式。在替换中常用$匹配组的内容。
3、常见功能
     1)匹配:String类中的booleanmatches(String regex)方法。用规则匹配整个字符串,只要有一处不符合规则,就匹配结束,返回false。
   
2)切割:String类中的String[]split(String regex)方法。
 
  按叠词完成切割:为了让规则被重用,可将规则封装成一个组,用()完成。组的出现都有编号,从1开始。想要使用已有的组可通过\n(n就是组的编号)的形式来获取。
        对于组中所匹配的字符,可以用$n来获取。$在正则中表示行的结尾,所以出现在正则中不能用来表示组,一般用于替换中。
3)替换: String replaceAll(String regex,String replacement)方法。
          
4)获取:将字符串中的符合规则的子串取出。
操作步骤:
        1)将正则表达式封装成对象。
        2)让正则对象和要操作的字符串相关联。
        3)关联后,获取正则匹配引擎。
        4)通过引擎对符合规则的子串进行操作,比如取出


Java正则表达式有3中量词匹配模式:
1.贪婪量词:
先看整个字符串是否匹配,如果没有发现匹配,则去掉最后字符串中的最后一个字符,并再次尝试,如果还是没有发现匹配,那么,再次去掉最后一个字符串的最后一个字符,整个匹配过程会一直重复直到发现一个匹配或者字符串不剩任何字符。简单量词都是贪婪量词。
贪婪量词匹配时,首先将整个字符串作为匹配的对象,然后逐步从后向前移除不匹配的字符,尽可能找到最多的匹配。
2.惰性量词:
先看字符串中的第一个字符是否匹配,如果单独一个字符不够,则读入下一个字符,组成两个字符的字符串,如果还没有发现匹配,惰性量词继续从字符串中添加字符直到发现一个匹配或者整个字符串全部检查完都不匹配。惰性量词和贪婪量词工作方式恰好相反。
惰性量词匹配时,只匹配第一个字符,然后依次添加字符,尽可能找到最少匹配。
3.支配量词:
只尝试匹配整个字符串,如果整个字符串不能产生匹配,则不进行进一步尝试。
支配量词目前只有java中支持,支持量词是贪婪量词第一次匹配不成功时,阻止正则表达式继续匹配,使得正则表达式效率更高。
贪婪量词              惰性量词              支配量词                         描述
X?                           X??                       X?+                    X出现0次或者1次
X*                           X*?                        X*+                     X出现0次或者多次
X+                          X+?                       X++                     X出现1次或者多次
X{n}                       X{n}?                    X{n}+                   X只出现n次
X{n,}                      X{n,}?                   X{n,}+                X至少出现n次
X{n,m}                  X{n,m}?               X{n,m}+                 X至少出现n次,至多不超过m次

正则表达式提供一种完全通用的方式,能够解决各种字符串处理相关的问题:匹配,选择,编辑,验证。
\d表示一位数字。
普通的反斜线:\\
换行和制表符:单反斜线\n\t
表示一个或多个之前的表达式:+
可能有一个负号:后面跟着一位或多位数字:-?\d+
System.out.pritln("-1234".matches("-?\\d+"));
1
括号有着表达式分组的效果,而竖直线|则表示或操作。
(-|\+)?
因为字符+在正则表达式中有特殊的意义,所以必须使用\将其转义。使之成为表达式中的一个普通字符。
String类型还自带了一个非常有用过得正则表达式工具—split()方法,其功能是“将字符串从正则表达式匹配的地方切开”。
String s="i love China";
s.split(" ");
1
2
\W非单词字符
\w一个单词字符
String还自带的一个正则表达式工具是“替换”,你可以只替换正则表达式第一个匹配的子串,或是替换所有匹配的地方。
String s="you can make much money";
s.replaceFirst("c\\w+","must");
s.replaceAll("you|I","everyone")
1
2
3
以大写字母开头,以句号结尾:^[A-Z]\?
用下划线替换元音字母
s.replaceAll(“a|e|i|o|u”,”_”);
可参考JDK文档中java.util.regex包中的Pattern类。
字符
B 指定字符B
\xhh 十六进制值为oxhh的字符
\uhhhh 十六进制表示为oxhhhh的Unicode字符
\t 制表符Tab
\n 换行符
\r 回车
\f 换页
\e 转义(Escape)
字符类
. 任意字符
[abc] 包含a、b和c的任何字符(和a|b|c作用相同)
[^abc] 除了a、b和c之外的任何字符(否定)
[a-zA-Z] 从a到z或从A到Z的任何字符(范围)
[abc[hij]] 包含a、b、c、h、i和j的任何字符(和a|b|c|h|i|j作用相同)(合并)
[a-z&&[hij]] 任意h、i或j(交)
\s 空白符(空格、tab、换行、换页和回车)
\S 非空白符([^\s])
\d 数字[0-9]
\D 非数字[^0-9]
\w 词字符[a-zA-Z0-9]
\W 非词字符[^\w]
逻辑操作符
XY Y跟在X后面
X|Y X或Y
(X) 捕获组。可以在表达式中用\i引用第i个捕获组
边界匹配符
^ 一行的起始
$ 一行的结束
\b 词的边界
\B 非词的边界
\G 前一个匹配的结束
量词
贪婪型
X? 一个或零个X
X* 零个或多个X
X+ 一个或多个X
X{n} 恰好n次X
X{n,} 至少n次X
X{n,m} X至少n次,且不超过m次

为什么不可变,通过他人写的内容进行补充一下。
public class TestString {
static String upcase(String s){
return s.toUpperCase();
}
public static void main(String[] args) {
String s = "bbc";
String ss = upcase(s);
System.out.println(s);
}
}

这里虽然s传参给了upcase方法,但是s并没有改变,传参的时候,s会复制一份引用,但是引用所指的对象却没有移动过。

再补充一下一些特别的东西。
由Java编程思想(一) —— 一切都是对象 知道,内存分配中,堆是存放对象的地方,而对内存中还有一块特殊的存储区域,而常量存储区存储的是便有字符串,所以:

String a = "a";
String b = "b";
虽然a,b看似两个不同的引用,存在栈区,但其实指向的都是堆中同样的String对象。

再看看这个:
public static void main(String[] args) {
String s= "s";
String s2= "s";
String s3= new String("s");
String s4= new String("s");
System.out.println(s==s2);
System.out.println(s3==s2);
System.out.println(s3==s4);
}
==比较的是两个对象的地址,其实由上面的a,b指向同一对象知道,s==s2,而new String呢,不会理你堆中是不是有同样的"s"对象,没每new一次,都重新创建一个,所以s3,s4,s2是不会==的。

2)重载“+”与StringBuilder
其实,StringBuilder和StringBuffer的东西,在面试笔试题里面已经看过很多遍了,但是,但是,每次都会忘记,这属性的东西,虽然一测试可以知道效率问题,但是直接回答还是凭借记忆。前段时间在知乎看到一个在外国工作的女程序员妹纸用了英文的记忆,当时记住了,答案现在找不到。

public class Test{
        public static void main(String[] args) {
        String s = "bbc";
       
        String ss = "ddt"+s+"sdf"+3;
        System.out.println(ss);
    }
}


F:\>javac Test.java
F:\>javap -c Test
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":
()V
4: return

public static void main(java.lang.String[]);
Code:
0: ldc #2 // String bbc
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<
init>":()V
10: ldc #5 // String ddt
12: invokevirtual #6 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_1
16: invokevirtual #6 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: ldc #7 // String sdf
21: invokevirtual #6 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: iconst_3
25: invokevirtual #8 // Method java/lang/StringBuilder.ap
pend:(I)Ljava/lang/StringBuilder;
28: invokevirtual #9 // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
31: astore_2
32: getstatic #10 // Field java/lang/System.out:Ljava/
io/PrintStream;
35: aload_2
36: invokevirtual #11 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
39: return
}

作者还真是厉害,反编译class,出来一大堆汇编,之前学过8086的看起来还是挺面熟的,代码里面发现竟然自己调用了StringBuilder。因为跟作者所说的思路,如果+是String的append反复,那么每每加上一个之后就会有新对象,最后产生很多没用的对象。

竟然默认调用了StringBuilder,那么是不是可以全部都用重载+呢?
public class Test{
   public String plus(String[] array){
        String s = null;
        for (int i = 0; i < array.length; i++) {
            s += array[i];
        }
        return s;
    }
    
    public String builder(String[] array){
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < array.length; i++) {
            sb.append(array[i]);
        }
        return sb.toString();
    }
}

反编译:
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":
()V
4: return

public java.lang.String plus(java.lang.String[]);
Code:
0: aconst_null
1: astore_2
2: iconst_0
3: istore_3
4: iload_3
5: aload_1
6: arraylength
7: if_icmpge 37
10: new #2 // class java/lang/StringBuilder
13: dup
14: invokespecial #3 // Method java/lang/StringBuilder."<
init>":()V
17: aload_2
18: invokevirtual #4 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: aload_1
22: iload_3
23: aaload
24: invokevirtual #4 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
27: invokevirtual #5 // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
30: astore_2
31: iinc 3, 1
34: goto 4
37: aload_2
38: areturn

public java.lang.String builder(java.lang.String[]);
Code:
0: new #2 // class java/lang/StringBuilder
3: dup
4: invokespecial #3 // Method java/lang/StringBuilder."<
init>":()V
7: astore_2
8: iconst_0
9: istore_3
10: iload_3
11: aload_1
12: arraylength
13: if_icmpge 30
16: aload_2
17: aload_1
18: iload_3
19: aaload
20: invokevirtual #4 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: pop
24: iinc 3, 1
27: goto 10
30: aload_2
31: invokevirtual #5 // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
34: areturn
}

有没有发现,有默认的空参数的构造器Test();
plus方法,34 goto 4,4是i的初始化,然后再接下去运行,比较,不停地跳转,StringBuilder在循环中不停的构建。这样就有很多的StringBuilder对象浪费了。注意10那里,new的创建。

在看看,反汇编之后的build方法,循环中是没有new东西的,就只有一个StringBuilder对象。

这样分析之后,明显StringBuider在不停地对字符串进行操作是效率更高资源占用少的,如果只是简单的几个字符串合并,那可以用+。

这个例子用了反汇编之后看起来简单好多,其实有些比较是通过时间计算,当然也是可以的。

StringBuilder是在SE5版本引入,之前用的是StringBuffer,这笔试题经常有的东西,出现了,StringBuffer是线程安全的,这样开销就比StringBuilder大,所以不存在线程问题的时候,使用StringBuilder。
可以看看下面那个网址,这是知乎上的一个叫程序猎人写的(由化学读软件,这是一个很牛逼的选择)。里面就是StringBuffer VS StringBuilder。
https://gist.github.com/programus/1978494

这一看发现GitHub原来还有Gist这样好用的东西。类似于保存零散代码的仓库。


3)常用方法
String实现三个接口。
CharSequence:
charAt(int i), 返回字符串中该索引指向的字符。
length,字符串长度返回。
subSequence(int start, int end) ,返回索引从start开始end结束的字符串。
toString().

Comparable:
compareTo(T o) ,x.compareTo(y),这样比较。

.正则表达式初步
    1-1split()方法的使用,参数为正则表达式
        用途:分割字符串
 JDK:      
split
public String[] split(String regex)
根据给定正则表达式的匹配拆分此字符串。
该方法的作用就像是使用给定的表达式和限制参数 0 来调用两参数 split 方法。因此,所得数组中不包括结尾空字符串。
例如,字符串 "boo:and:foo" 使用这些表达式可生成以下结果:
Regex 结果
: {
"boo", "and", "foo" }
o { "b", "", ":and:f" }
参数:
regex - 定界正则表达式
返回:
字符串数组,它是根据给定正则表达式的匹配拆分此字符串确定的 
public class Test14 {
public static void main(String[] args){

String ss = "abc dsadsa sdas sda asd";
//String[] s = ss.split(" {1,}");
String[] s = ss.split(" +");

for(int i = 0; i < s.length;i++)
System.out.println(s[i]);


}
}
结果:
abc
dsadsa
sdas
sda
asd
package NO2;

public class Test14 {
public static void main(String[] args){

String ss = "abc+dsadsa+sdas+sda+asd";
//String[] s = ss.split(" {1,}");
//String[] s = ss.split("\\+");
String[] s = ss.split("\\+");

for(int i = 0; i < s.length;i++)
System.out.println(s[i]);

//System.out.println("\\+");
}
}
在正则表达式中表示分隔符"+", 需要表示成"\+"
而在java中"\"为转义符,故上面ss.spilit("\\+")参数为 "\\+"
    1-2.match函数  用途:匹配字符串(判断是否匹配正则表达式)
JDK:
matches
public boolean matches(String regex)
告知此字符串是否匹配给定的正则表达式。
调用此方法的 str.matches(regex) 形式与以下表达式产生的结果完全相同:
Pattern.matches(regex, str)
参数:
regex - 用来匹配此字符串的正则表达式
返回:
当且仅当此字符串匹配给定的正则表达式时,返回 true
public class Test15 {

public static void main(String[] args) {
// TODO Auto-generated method stub
String ss = "AZ125";
boolean flag = ss.matches("[A-Z]{1,2}[1-9]{1,5}"); //{1,2}分别为表示出现的最小,最大次数
//+表示{1,}(最小1次,最多不限) *表示{0,} ?表示{0,1}
//+ * ?在正则表达式中成为量词(不能直接表示它本身),如要在正则表达式中表示它本 //身,则需要转义
//如"+" 应该表示为"\\+"
System.out.println(flag);

}

}
结果:true
        1-3 replaceAll  用途:替换
replaceAll
public String replaceAll(String regex,
String replacement)
使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
调用此方法的 str.replaceAll(regex, repl) 形式与以下表达式产生的结果完全相同:
Pattern.compile(regex).matcher(str).replaceAll(repl)
注意,在替代字符串中使用反斜杠 (\) 和美元符号 ($) 与将其视为字面值替代字符串所得的结果可能不同;请参阅 Matcher.replaceAll。如有需要,可使用 Matcher.quoteReplacement(java.lang.String) 取消这些字符的特殊含义。
参数:
regex - 用来匹配此字符串的正则表达式
replacement - 用来替换每个匹配项的字符串
返回:
所得 String
public class Test16 {
public static void main(String[] args) {


String ss = "adasdasd 2015-9-12 33adsd dasdasdwe";
String strings = ss.replaceAll("[0-9]{4}-[0-9]{1}-[0-9]{2}","****");

System.out.println(strings);

}

}
结果:adasdasd   **** 33adsd dasdasdwe
在正则表达式中,用括号括起来的部分称为 :子组
  

将 2015-9-12 替换为 9/12 2015年

public class Test16 {
public static void main(String[] args) {


String ss = "adasdasd 2015-9-12 33adsd dasdasdwe";
//String strings = ss.replaceAll("[0-9]{4}-[0-9]{1}-[0-9]{2}","****");// 9/12 2015年
String strings = ss.replaceAll("([0-9]{4})-([0-9]{1})-([0-9]{2})", "$3/$2 $1年");
System.out.println(strings);

}

}

   1-4 replaceFirst 
replaceFirst
public String replaceFirst(String regex,
String replacement)
使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
调用此方法的 str.replaceFirst(regex, repl) 形式与以下表达式产生的结果完全相同:
Pattern.compile(regex).matcher(str).replaceFirst(repl)
注意,在替代字符串中使用反斜杠 (\) 和美元符号 ($) 与将其视为字面值替代字符串所得的结果可能不同;请参阅 Matcher.replaceFirst(java.lang.String)。如有需要,可使用 Matcher.quoteReplacement(java.lang.String) 取消这些字符的特殊含义。
参数:
regex - 用来匹配此字符串的正则表达式
replacement - 用来替换第一个匹配项的字符串
返回:
所得 String

你可能感兴趣的:(java编程思想)