题目
分别编写名字为TestPackageCalss和MyException类,实现一下功能:在控制台串中输入一串字符,并判断,如果是整数字符串,则转换成Ingeger对象,如果是浮点数字符串则转换成Double对象,并格式化为 $#....#.##(不用四舍五入输出进度到小数点后面两位),如果是非数字,则抛出显式抛出自定义异常类MyException,异常信息是“输入了数据无法实现数字格式转换"。
(作业题,描述不太严谨,按照大概意思来即可)
说明
这个作业题不是重点,本博客重点是:以该题目为切入点,如何去写校验【正整数】和【浮点数】格式的正则表达式。正则表达式一般去网上找就行了,但掌握正则表达式的基础知识并会写简单的正则表达式也比较重要。
分析
1.整数
问:如何理解正确的整数格式?
举例:0,-1235,102340。。。这个不好说,只能靠意会
问:什么是不正确的整数格式?
举例:000,-0,+0,03524。。。显然一般来说,正确的整数格式是:不会有前导0的
先来看看网上找到的一个校验整数的正则表达式
String regex="^-?\\d+$";
还算比较简单吧。很容易看出来,这个正则表达式会错判有前导0的情况,会认为000,-0,+0,03524...这些是正确。
仅仅从作业题来看,Java种的 Integer.valueOf(str) 的 str 是允许前导0的,str 有前导0,该函数也能成功转换,并不会抛出异常。那么如果只是为了做这个作业题,这个正则表达式够用了。
假设OJ上有这么一题:
题目
请编写程序,判断给出的字符串是否符合正确的整数格式。
正确的整数格式:0,-1235,102340。。。
不正确的整数格式:000,-0,+0,03524。。
输入格式
每一行输入一个字符串,输入若干行。
输出格式
符合格式输出“yes”,否则输出“no”。
C/C++肯定是可以做的,但不好做。对于学习C/C++的同学来说,这是一道不错的考察字符串的题目。
铺垫了这么多。进入正题。
正确的整数格式分两种情况来考虑
(1)0。为什么0如此特殊以至于单独作为一种情况?因为防止这样的数据:-0,000,00。。。
(2)非0。有没有负号都是可以的,但第一位数字必定是[1-9],因为不能有前导0!随后的数位可以是[0-9]。
总结出规律,那么这个正则表达式就非常简单了
String regex="(-?[1-9]\\d*)|0";
2.浮点数
显然校验浮点数比校验整数复杂得多。考虑的情况很多,可能会有点乱。所以思考的时候注重角度。
明确一点:小数点只是正确的浮点数的格式的一个显著特征,一个符合正确格式的浮点数不一定要有小数点
例如:1.0符合浮点数的格式,1也认为是正确的浮点数格式。
可以这样认为:符合整数格式的字符串都符合浮点数格式。
正确的浮点数格式,分两个角度来考虑
(1)整数部分
浮点数的整数部分的校验能否直接搬上面校验整数的正则表达式?
不可以!为什么?
举例:-0.68是正确的浮点数格式,但如果搬上面的正则表达式校验其整数部分,-0.68会被认为有前导0而被错判!
整数部分的正则表达式:-?(0|[1-9]\\d*)
注意对比以下校验正整数的正则表达式,体会以下有什么不同?对比以下,可以看出0放在括号里面了,就是为了考虑到-0.68这种情况。
(2)小数部分
小数部分就非常简单了:(\\.\\d+)?
只要有小数点,后面必须有至少一位数字[0-9]。前面也说了,由于小数部分不是必须的,所以括起来然后加了个?
另外注意:由于“.”有特殊含义,在正则表达式表示:除了换行符以外的任意一个字符。故需要转义。
可以这样理解 “\\.”:① “\\” 转义成 “\ ”;② “\.” 转义成 “.”
合起来得到
String regex="-?(0|[1-9]\\d*)(\\.\\d+)?";
但是
这个正则表达式仍会错判一个特殊情况:-0。 但它不会错判-00,-000。。。
想想为什么?
假如有小数部分,整数部分是可以允许是-0的。假如没有小数部分,整数部分不能是-0!正则表达式在校验整数部分时,还不知道后面有没有小数部分。
如何规避这种情况?
重新分类,重写正则表达式?
没必要。
若想在正则表达式中规避-0的情况,就要另外分类,将-0的情况单独分处理,但如果这样去干正则表达式就会变得冗长,
且分类多了就容易重叠混乱,造成越想追求完美结果就越多bug的得不偿失。既然只有这一种特例,如果需要,在正则
表达式外面特判即可。
代码
下面给出这个作业题的完整代码。
package theme4;
import java.text.DecimalFormat;
import java.util.Scanner;
/**
* 分别编写名字为TestPackageCalss和MyException类,实现一下功能:在控制台串中输入一串字符,并判断,
* 如果是整数字符串,则转换成Ingeger对象,如果是浮点数字符串则转换成Double对象,并格式化为 $#....#.##
* (不用四舍五入输出进度到小数点后面两位,),如果是非数字,则抛出显式抛出自定义异常类MyException,
* 异常信息是“输入了数据无法实现数字格式转换";
*/
public class TestPackageCalss {
public static void main(String[] args) {
//System.out.println(isDoubleFormat("-00"));
testInteger();
testDouble();
}
public static void testInteger()
{
System.out.println("请输入一个符合正确格式的整数字符串:");
Scanner sc=new Scanner(System.in);
String num=sc.nextLine();
try {
Integer intObj=strToInteger(num);
System.out.println("成功将字符串转成Integer对象");
System.out.println(intObj);
} catch (MyException e) {
System.out.println(e.getMessage());
} finally {
sc.close();
}
}
public static void testDouble()
{
System.out.println("请输入一个符合正确格式的浮点数字符串:");
Scanner sc=new Scanner(System.in);
String num=sc.nextLine();
try {
Double doubleObj=strToDouble(num);
String pattern="#.00";
DecimalFormat myFormat=new DecimalFormat(pattern);
System.out.println(myFormat.format(doubleObj));
} catch (MyException e) {
System.out.println(e.getMessage());
} finally {
sc.close();
}
}
public static Integer strToInteger(String num) throws MyException
{
if(isIntegerFormat(num))
return Integer.valueOf(num);
else
throw new MyException("字符串格式异常");
}
public static Double strToDouble(String num) throws MyException
{
if(isDoubleFormat(num))
return Double.valueOf(num);
else
throw new MyException("字符串格式异常");
}
public static boolean isIntegerFormat(String num)
{
String regex="(-?[1-9]\\d*)|0";
return num.matches(regex);
}
public static boolean isDoubleFormat(String num)
{
String regex="-?(0|[1-9]\\d*)(\\.\\d+)?";
if(num.equals("-0"))
return false;
return num.matches(regex);
}
}
package theme4;
/**
* 自定义异常类
* @author passerbyYSQ
*
*/
public class MyException extends Exception {
static final long serialVersionUID = -33875169934229948L;
public MyException()
{
}
public MyException(String msg)
{
super(msg);
}
}
备注
自己写的正则表达式,没有严格测试过。如有错误,轻喷。。