Java编程思想——细话Java中的字符串处理

一、String

      String为了可以节省存储空间以及避免额外的开销,在需要改变字符串内容时会返回一个新的字符串对象,而如果不需要改变字符串内容,则直接返回原对象的引用。这一点也许也解释了String对象为什么是不可改变的。

       String类在实际开发中使用频率非常高,其构造器和常用方法非常多,需要我们在开发中多多使用才能熟悉,具体可以参考如下地址查看:

http://tool.oschina.net/apidocs/apidoc?api=jdk-zh

        前几天看了一篇关于JDK9的新特性的博客,介绍了在1.9版本中对String进行了优化,主要是对字符表示进行了一定的调整(即从char——byte),也就是由char数组存放改为byte数组。在1.9之前无论中文还是英文都是采用双字节表示的,但是一个英文字母(包括ISO-8859-1编码内的所有字符)实际只需要一个字节就能进行存储,如果采用俩个字节存储就浪费了。所以在1.9版本后对ISO-8859-1编码内的字符采用1个字节存储,一旦出现编码外的字符就会采用双字节(当然,与编码外以通出现的编码内的字符也同样采用双字节)。所以对于都采用编码内字符开发的项目而言,优化效果是比较明显的,而对于中文而言没有任何变化。

二、类型转换——Formatter(java.util.Formatter)

d——整数型(十进制)e——浮点数(科学计数)
c——Unicode字符x——正数(十六进制)
b——Boolean值h——散列码(十六进制)
s——String

%——字符“%”

f——浮点数(十进制)

1.Formatter.format()

public class test{
   public static void main(String[] args){
	Formatter f=new  Formatter(System.out);//传入的参数告诉它最终的结果将向哪里输出
	int number=180;
	f.format("d: %d\n",number);
	f.format("c: %c\n",number);
	f.format("b: %b\n",number);//只要值不为null,转化结果都为true,即使是0转换结果也为true
	f.format("s: %s\n",number);
	//f.format("e: %e\n",number);
	f.format("x: %x\n",number);
	f.format("h: %h\n",number);
    }
}


2.String.format()

——静态方法(当只需使用format()方法一次时,推荐使用此方法),内部仍然是先创建一个Formatter,然后将传入的参数转给Formatter。

public class Love{
private String name="li_love_wang";
    public static void main(String[] args){
	test s=new test();
	String finalStr=String.format("%d %s %d forever!",520,s.name,1314);//返回一个String对象
    }
}

3.格式的精细化修饰

      除了上边的格式转换之外,Formatter还可以进行更加精细复杂的格式修饰,如控制一个域的最大、最小尺寸。Formatter对象会在必要时通过添加空格来确保一个域至少达到某个长度。在默认情况下,数据是右对齐,同时可以通过使用“-”标志来改变对齐方向

     %[对齐方式,默认右对齐,+“-”左对齐][width][.precision][转换类型符] 

    eg:%15s

    eg:  %15.15s

  • width——指明转换格式的最小尺寸,可以应用于任何的格式转换。
  • precision——指明最大尺寸,适用于某些格式。例如,不适合用于整数,会触发异常。用于字符串表示输出字符的最大数量,不够补空格;浮点数,控制小数部分的位数(默认6位),若小数位过多则舍去,不够则补零。
Formatter f=new  Formatter(System.out);
f.format("%3s%10s%10s%10s\n","name","sex","age","phone");
f.format("%-3s%10s%10s%10s\n","----","---","---","-----");
f.format("%-13s%-9s%-7s%5s\n","BigTomCat","m","22","13233330521");
f.format("%-13s%-9s%-7s%5.5s\n","Jack","m","24","13233330522");
f.format("%-13s%-9s%-7s%s\n","Rose","w","21","13233330523");


4.Java中格式化的三种形式

	//format:"520forever![love you:1314]"
	String output="love you";
	int love=520;
	int time=1314;
	//通过字符串拼接
	System.out.println(love+"forever!["+output+":"+time+"]");
	//通过C中的格式化方法
	System.out.printf("%dforever![%s:%d]\n",love,output,time);
	//format()是模仿printf()方法创建的
	System.out.format("%dforever![%s:%d]\n",love,output,time);

三、正则表达式

1.正则表达式的简单应用

正则表达式提供了一种完全通用的方式,能够解决各种字符串处理相关的问题:匹配、选择、编辑以及验证。Java中与其他语言不同的是用“\\”表示在插入一个正则表达式的反斜杠,如果表示以为数字则需要写为“\\d”,不过对于换行符和制表符和其他语言一样,直接写成“\n”和“\t”即可。简单的正则表达式格式如下所示:

  • \\W——非单词字符
  • \\w——表示一个单词字符
  • n\\W+——表示字母n后面跟着一个或多个非单词字符
  • f\\w+——表示f开头的后边跟一个或多个字母

String中含有使用正则表达式处理字符串的方法:

  • split([分割规则])——通过指定的分割标准进行字符串的分割,这些标准通常使用正则表达式描述
        //format:"520forever![love you:1314]"
	String output="love you";
	int love=520;
	int time=1314;	
	String str=String.format("%dforever![%s:%d]\n",love,output,time);  //通过String.format()进行格式化返回一个String对象
	System.out.println(Arrays.toString(str.split("o\\w")));  //返回的String对象调用split()方法进行字符串分割
	System.out.println(Arrays.toString(str.split("o")));     //"o"在正则表达式中没有特殊含义,所以不需要进行转义


  • replaceFirst([替换条件])——替换字符串中第一个符合此条件的部分
  • replaceAll([替换条件])——替换所有符合条件的部分
        //format:"520forever![love you:1314]"
	String output="love you";
	int love=520;
	int time=1314;	
	String str=String.format("%dforever![%s:%d]\n",love,output,time);//格式转换返回String对象
	System.out.println(str.replaceFirst("o\\w+","love".toUpperCase()));//首个单词替换
	System.out.println(str.replaceAll("o\\w+","love".toUpperCase()));//全部替换

2.创建正则表达式

就和一般的语言一样,要想创建必须要知道其本身的组成元素和语法,下面总结一些正则表达式中常用的元素:

字符
B指定字符B(其他字母的含义一样,如A、C等)
\xhh十六进制值为oxhh的字符,如:\x12e
\uhhhh十六进制表示为oxhhhh的Unicode字符
\t制表符Tab
\n换行符
\r回车
\f换页
\e转义
字符类
[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-z&&[hij]]任意h,i或j(交)
\s表示所有的空白符(空格,tab,换行,换页和回车)
\S非空白符([^\s])
\d数字[0-9]
\D非数字[^0-9]
\w词字符[a-zA-Z0-9]
\W非词字符[^\w]
逻辑操作符
XYY跟在X后面,如ab
X|YX或Y
(X)捕捉组。可以在表达式中用“\i”引用第i个捕获组
边界匹配符
^一行的起始
\B非词的边界
$一行的结束
\G前一个匹配的结束
\b词的边界

量词
贪婪型勉强型占有型如何匹配
X?X??X?+一个或零个X
X*X*?X*+零个或多个X
X+X+?X++一个或多个X
X{n}X{n}?X{n}+恰好n次X
X{n,}X{n,}?X{n,}+至少n次X
X{n,m}X{n,m}?X{n,m}+X至少n次,但不能超过m次

何为量词(字符串匹配中常用的工具):

量词描述了一个模式吸收输入文本的方式。

  • 贪婪型(最大匹配):——Java中的默认匹配类型

       会为所有可能的模式发现尽可能多个匹配。也就是当匹配到一个目标后会继续向下进行下去。

  • 勉强型(最小匹配):

       用问号来指定,满足模式所需的最少字符串个数,因此被称作懒惰的、非贪婪的或不贪婪的。(添加?)

  • 占有型(完全匹配):

       目前只在Java存在,为更高级的一种模式。因”占有的“量词并不保存这些中间状态,因此它们可以防止回溯。它们常常用于防止正则表达式失控,因此可以使正则表达式执行起来更有效。与贪婪型不同的是,贪婪型在一次匹配失败后会回溯回去然后缩小范围进行重新匹配,但占有型由于没有回溯,所以当一遍匹配失败后就不做匹配了。(添加+)

eg:

String strM="java<hello>this<world>";
//贪婪型
String reg1="<.+>";
//勉强型
String reg2="<.+?>";
//占有型
String reg3="<.++>";
System.out.println(strM.replaceAll(reg1,"***"));
System.out.println(strM.replaceAll(reg2,"***"));
System.out.println(strM.replaceAll(reg3,"***"));

可以很容易从这个例子看出三种模式的区别。

注:

abc+——代表ab后面跟随一个或多个c

(abc)+——代表匹配一个或多个abc

3. 正则表达式的使用

3.1静态字符序列中的应用
import java.util.regex.*;  //第一步先导入匹配包(使用Pattern和Matcher俩个类)

System.out.println("--------Pattern-----------");
String words="Arline ate eight apples and one orange while Anita hadn`t any"; //需要匹配的字符串
Pattern p=Pattern.compile("a\\w+(\\S+)\\s"); //通过compile([正则表达式])获取Pattern对象
Matcher m=p.matcher(words); //通过matcher()获的Matcher对象
while(m.find()){
	System.out.print(m.group()+":"+m.start()+"---"+(m.end()-1)+"\n");
}
System.out.println("groupCount():"+m.groupCount());
//System.out.print("group(int i):"+m.group(1));
System.out.println("find():"+m.find());
System.out.println("find(int i):"+m.find(1));
System.out.println("lookingAt():"+m.lookingAt());
System.out.println("matches():"+m.matches());
System.out.println("\n----------------------------");

例子中使用了常用的一些方法:

  • Pattern   Pattern.compile(Stirng str)——获取Pattern对象
  • Matcher  Pattern.compile(Stirng str).matcher(String str,int flag)——获取Matcher对象

*记”m“为Matcher的对象引用:

这些方法中涉及到一个组——组是用括号划分的正则表达式,可以根据组的编号来引用某个组(如:group(1)),组号为0表示整个表达式,组号为1表示被第一个括号括起来的组,其他以此类推。

A(B(C))D——此为3个组组成:组0是ABCD,组1是BC,组2是C。

  • int   m.groupCount()——获取组数
  • String m.group(int i)——返回指定组捕获的匹配的子序列
  • String m.group()——返回已匹配的字符序列
  • int   m.start()——获取当前匹配序列的开始位置
  • int   m.end()——获取当前匹配序列的结束位置+1
  • boolean   m.find()——是否匹配成功
  • boolean   m.find(int i)——指定位置是否匹配成功
  • boolean   m.lookingAt()——匹配的字符序列的开头是否匹配成功
  • boolean   m.matches()——判断输入的整个字符串是否匹配成功

*记”p“为Pattern的对象引用:

分割:Stirng[]   p.split(CharSequence input,int limit)——按照指定断开边界将字符系列input进行分割并返回一个字符串数组,int limit是一个可有可无的参数,当添加limit时指定到第几个位置处停止分割。

System.out.println("\n----------------------------");
String[] svector=Pattern.compile("!!").split("JAVA!!Android!!J2EE!!JAVASE");     //无limit
for(String subs:svector){
	System.out.println(subs);
}
System.out.println("----------");
String[] svector2=Pattern.compile("!!").split("JAVA!!Android!!J2EE!!JAVASE",3);   //有limit
for(String subs:svector2){
	System.out.println(subs);
}
System.out.println("\n----------------------------");


替换:

  • m.replaceFirst(String replacement)——替换第一个匹配成功的部分
  • m.replaceAll(Stirng replacement)——替换所有匹配成功的部分
  • m.appendReplacement(StringBuffer sbuf,String replacement)——执行渐进式的替换
  • m.appendTail(StringBuffer sbuf)——在执行了一次或多次appendReplacement()后,将输入字符串余下部分复制到sbuf中
  • m.reset(String squence)——可以将现有的Matsher对象应用于一个新的字符序列
System.out.println("\n----------------------------");
String neww=words.replaceFirst("[aeiou]","***");
System.out.println(neww);
String neww2=words.replaceAll("[aeiou]","*");
System.out.println(neww2);
StringBuffer sub=new StringBuffer();
Matcher mtc=Pattern.compile("[aeiou]").matcher(words);
while(mtc.find()){
	mtc.appendReplacement(sub,mtc.group().toUpperCase());
}
System.out.println(sub);
mtc.appendTail(sub);  //可将替换后剩余的字符保存到StringBuffer中
System.out.println(sub);
mtc.reset("hello world!"); //将之前需要替换的目标字符序列进行替换
while(mtc.find()){
	System.out.println(mtc.group());
}
System.out.println("\n----------------------------");

注:

  • 由于replaceFirst()和replaceAll()俩个方法在String中同样存在,所以直接使用String中的方法,这样由于不需要创建Matcher对象而节省了开销。
  • 为什么说appendReplacement()更强大呢,因为其在在替换中可以对要替换的目标进行特殊处理,如上边例子中将需要被替换的字符进行大写转换。
  • 当reset()中不添加参数时,可以将Matcher对象重新设置到当前字符序列的起始位置。
3.2数据扫描

当我们需要字符序列中的一些数字或者其他类型的数据进行操作时,最好的办法就是将我们需要的数据进行提取然后应用。JavaSE5之后可以通过使用Scanner类进行字符序列的扫描。

System.out.println("\n----------------------------");
Scanner sca=new Scanner("this is a book \n5 22.5"); //Scanner类可以接收任何类型的输入对象,包括File对象、InputStream、String等
System.out.println("say words:"+sca.nextLine());
System.out.println("the number of ticket:"+sca.nextInt());
System.out.println("the price of one ticket:"+sca.nextDouble());
System.out.println("\n----------------------------");

从运行结果可以看出Scanner可以自动的进行分词和翻译,并通过其一系列的next方法获取不同类型的数据。

当然,Scanner也可以设定我们自己的界定符来对数据进行分词:

System.out.println("\n----------------------------");
sca=new Scanner("12-- 24-- 48-- 96");
sca.useDelimiter("\\s*--\\s*");//此界定符表示在"--"前后有零个或多个空白符
while(sca.hasNextInt()){
	System.out.println(sca.nextInt());
}
System.out.println("----------------------------");

可以通过useDelimiter([正则表达式])来作为Scanner的界定符。

用正则表达式进行扫描:

import java.util.*;
import java.util.regex.*;
public class regex{
public static void main(String[] args) throws Exception{
       String text=
		"101.10.10.01@23/05/2018\n"+
		"101.10.10.02@23/05/2018\n"+
		"101.10.10.03@23/05/2018\n"+
		"101.10.10.04@23/05/2018\n"+
		"[this is a login log]"	;
	Scanner sc=new Scanner(text);
	String pattern="(\\d+[.]\\d+[.]\\d+[.]\\d+)+@+(\\d{2}/\\d{2}/\\d{4})";
	while(sc.hasNext(pattern)){
		sc.next(pattern);
		MatchResult result=sc.match();
		String ip=result.group(1);
		String time=result.group(2);
		System.out.format("Threat on %s from ip:%s\n",time,ip);
	}
}
}

3.3正则表达式与文件

      之前所有的操作都是通过正则表达式操作静态字符序列,那么我们如何将正则表达式应用到一个文件中进行搜索匹配呢?其实与静态字符串是一样的,我们可以先将文件中的数据读出来返回为String类型的或者其他数据流,然后循环通过Pattern和Matcher类进行匹配即可。

3.4正则表达式中的模式


在这些模式中,最常用的就是Pattern.CAZE_INSENSITIVE(?i)、Pattern.MULTILINE(?m)以及Pattern.COMMENTS(?x)(对声明和文档有用)。

实例:

System.out.println("----------------------------");
//Pattern pp=Pattern.compile("^java",Pattern.CASE_INSENSITIVE|Pattern.MULTILINE);
Pattern pp=Pattern.compile("(?i)(?m)^java");
//Pattern pp=Pattern.compile("(?i)^java");
//Pattern pp=Pattern.compile("(?m)^java");
Matcher mm=pp.matcher("java is a very good computer language\nJava has String \n"+
"Java has regex\njava has class\n"+
"I like it,if you do,we to lean Java together!");
while(mm.find()){
     System.out.println(mm.group());
}
System.out.println("----------------------------");






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值