Spads 出品字符串高效提取数值方法 Shane 末日圣诞奉献
2013-02-19 20:55
796 查看
Spads 出品,作者 WangXP 与 Shane
目录
---------- ---------- ---------- ----------
1 【综述】
2 【程序】
3 【功能】
4 【性能】
5 【附录】
1 【综述】
---------- ---------- ---------- ----------
最近因为继续编写公式处理和 Json - Java 互转组件,所以专门制作、优化了字符串变成数值的工具方法,并在性能上取得了领先于阿帕奇工具和爪哇类库等方式的成就。本方法基本思路是逐字符扫描。目前关于将字符串转为数值,市面上常见的资料,我搜索总结了十几篇吧,大体是重复的,包括这么几种方法。我看过的资料网址收集在附录中。
1、通过 Java 系统提供的 Character#isDigit(char) 判断是否为数值,然后转换。
2、通过正则表达式判断是否为数值,然后转换。
3、直接转换,捕捉异常。
4、阿帕奇提供了 isNumeric(String) 和 isNumericSpace(String) 方法用以判断。如果是数值再转换。
目前我这边的需求是,需要支持整数、数字间的空格、空白头尾、小数以及直接小数点开头的小数。
JavaLib 的 isDigit(char) 只能判断数字,所以需要事先去除空格、首位负号和第一个小数点。
正则表达式在转换前需要去除空格
直接转换前也需要去除空格
阿帕奇工具方法能判断数字和空格,所以需要事先去除首位负号和第一个小数点。
Spads 编写程序是直接利用了字符特点,扫描字符串。也可以认为是一种结合了预处理与字符 ASCII 判断的方法。本方法会将能够解析成数值的字符串解析成数值,否则返回 null 。
2 【程序】
---------- ---------- ---------- ----------
Spads 直接编写了适用的程序,经过很长时间性能优化,达到了优于上述所有方法的效果。代码如下。
Java代码
/**
* <b>抽取字符串的数字值</b><br/>
*
* 本方法用来将传入字符串的内容理解为十进制数值。如果传入字符串的内容无法理解为
* 数值,则返回 <code>null</code> 。数值字符串是指包括正、负的整数、浮点数;其中
* 允许出现分割用空格,允许直接使用小数点起头以表示 0.x 样的小数。<br/>
* 方法使用示例如下。
* <pre>
* StringTool.fetchNumberValue("15") = 15 (java.lang.Integer)
* StringTool.fetchNumberValue("300 1500 1010")
* = 30015001010 (java.lang.Long)
* StringTool.fetchNumberValue(" 28 ") = 28 (java.lang.Integer)
* StringTool.fetchNumberValue("3.8") = 3.8 (java.lang.Double)
* StringTool.fetchNumberValue("-99") = -99 (java.lang.Integer)
* StringTool.fetchNumberValue("+15") = null
* StringTool.fetchNumberValue(".45") = 0.45 (java.lang.Double)
* StringTool.fetchNumberValue("-.1") = -0.1 (java.lang.Double)
* StringTool.fetchNumberValue("0x3AFF0") = null
* StringTool.fetchNumberValue("042") = 42 (java.lang.Integer)
* StringTool.fetchNumberValue("Spads") = null
* StringTool.fetchNumberValue("") = null
* StringTool.fetchNumberValue(null) = null
* StringTool.fetchNumberValue("5 - 3") = null
* StringTool.fetchNumberValue("3.1415926.5358") = null
* StringTool.fetchNumberValue("13205972138597109830758190748937102794")
* = 1.320597213859711E37 (java.lang.Double)
* </pre>
*
* 本方法不涉及正则表达式,同时未避免生成异常的巨大系统消耗,通过遍历字符串每
* 一个字符来判断其是否符合十进制数值格式,格式不符则直接返回
* <code>null</code> 。如果格式符合,浮点数按 {@link Double} 识别,整数按
* {@link Long} 识别。如果数值范围符合 {@link Integer} ,则转换。
*
* @see StringTool#removeChar(String, char)
* @param numStr 准备提取数值的字符串
* @return 传入字符串按十进制理解的数值对象,其类型有可能为
* <code>Long</code> 、 <code>Integer</code> 或者 <code>Double</code>。
* @exception NumberFormatException 当字符串是整数但超过了
* {@link Long#MIN_VALUE} - {@link Long#MAX_VALUE} 范围同时其位数并不大于 20,
* 或者字符串是浮点数 但超过了
* {@link Double#MIN_VALUE} - {@link Double#MAX_VALUE} 范围。
*/
static public Number parseNumber(String numStr)
{
if (numStr == null || (numStr = numStr.trim()).length() ==
0)
return null;
final StringBuilder numBuilder =
new StringBuilder();
boolean doubleFlag = false;
final int length = numStr.length();
char numChar;
for (int index =
0; index != length; index++)
{
numChar = numStr.charAt(index);
if (numChar > 57)
return null;
switch (StringTool.charType[numChar])
{
// 在之前没有小数点的情况下出现小数点,记录,同时认为此字符串是浮点数
case 3:
if (doubleFlag || index == length -
1) return null;
doubleFlag = true;
// 此处通过
// 如果是数字,认为此字符串还是数值,检查下一个字符
case 4: numBuilder.append(numChar);
// 此处通过
// 如果是空格,直接检查下一个字符
case 1:
continue;
// 如果是负号,又不是首位,则按非数值字符串进行返回
case 2:
if (index == 0)
{
numBuilder.append(numChar);
continue;
}
// 此处通过
// 如果字符不符合数值格式,方法按非数值字符串进行返回
case 0:
return null;
}
}
if (doubleFlag || length >
20)
return Double.valueOf(numBuilder.toString());
// 非浮点数情况,如果数值在整数范围内,则按整数返回。否则按长整数返回。
final long num = Long.parseLong(numBuilder.toString());
final int finalNum = (int) num;
if (finalNum != num) return num;
return finalNum;
}
/**
* <b>字符类型数组</b><br/>
* 为字符串抽取数值含义提供的字符类型获取器。通过将字符本身作为此数组下标获取对应
* 类型。类型用整数表示,含义如下。<br/>
* 1 为空白间隔,对应 <code>' '</code> 和 <code>'\t'</code><br/>
* 2 为负号,对应 <code>'-'</code><br/>
* 3 为小数点,对应 <code>'.'</code><br/>
* 4 为数字,对应 <code>'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'</code>
*/
static private
int[] charType = {
0,0,0,0,0,
0,0,0,0,1,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,1,0,0,
0,0,0,0,0,
0,0,0,0,0,
2,3,0,4,4,
4,4,4,4,4,
4,4,4
};
目录
---------- ---------- ---------- ----------
1 【综述】
2 【程序】
3 【功能】
4 【性能】
5 【附录】
1 【综述】
---------- ---------- ---------- ----------
最近因为继续编写公式处理和 Json - Java 互转组件,所以专门制作、优化了字符串变成数值的工具方法,并在性能上取得了领先于阿帕奇工具和爪哇类库等方式的成就。本方法基本思路是逐字符扫描。目前关于将字符串转为数值,市面上常见的资料,我搜索总结了十几篇吧,大体是重复的,包括这么几种方法。我看过的资料网址收集在附录中。
1、通过 Java 系统提供的 Character#isDigit(char) 判断是否为数值,然后转换。
2、通过正则表达式判断是否为数值,然后转换。
3、直接转换,捕捉异常。
4、阿帕奇提供了 isNumeric(String) 和 isNumericSpace(String) 方法用以判断。如果是数值再转换。
目前我这边的需求是,需要支持整数、数字间的空格、空白头尾、小数以及直接小数点开头的小数。
JavaLib 的 isDigit(char) 只能判断数字,所以需要事先去除空格、首位负号和第一个小数点。
正则表达式在转换前需要去除空格
直接转换前也需要去除空格
阿帕奇工具方法能判断数字和空格,所以需要事先去除首位负号和第一个小数点。
Spads 编写程序是直接利用了字符特点,扫描字符串。也可以认为是一种结合了预处理与字符 ASCII 判断的方法。本方法会将能够解析成数值的字符串解析成数值,否则返回 null 。
2 【程序】
---------- ---------- ---------- ----------
Spads 直接编写了适用的程序,经过很长时间性能优化,达到了优于上述所有方法的效果。代码如下。
Java代码
/**
* <b>抽取字符串的数字值</b><br/>
*
* 本方法用来将传入字符串的内容理解为十进制数值。如果传入字符串的内容无法理解为
* 数值,则返回 <code>null</code> 。数值字符串是指包括正、负的整数、浮点数;其中
* 允许出现分割用空格,允许直接使用小数点起头以表示 0.x 样的小数。<br/>
* 方法使用示例如下。
* <pre>
* StringTool.fetchNumberValue("15") = 15 (java.lang.Integer)
* StringTool.fetchNumberValue("300 1500 1010")
* = 30015001010 (java.lang.Long)
* StringTool.fetchNumberValue(" 28 ") = 28 (java.lang.Integer)
* StringTool.fetchNumberValue("3.8") = 3.8 (java.lang.Double)
* StringTool.fetchNumberValue("-99") = -99 (java.lang.Integer)
* StringTool.fetchNumberValue("+15") = null
* StringTool.fetchNumberValue(".45") = 0.45 (java.lang.Double)
* StringTool.fetchNumberValue("-.1") = -0.1 (java.lang.Double)
* StringTool.fetchNumberValue("0x3AFF0") = null
* StringTool.fetchNumberValue("042") = 42 (java.lang.Integer)
* StringTool.fetchNumberValue("Spads") = null
* StringTool.fetchNumberValue("") = null
* StringTool.fetchNumberValue(null) = null
* StringTool.fetchNumberValue("5 - 3") = null
* StringTool.fetchNumberValue("3.1415926.5358") = null
* StringTool.fetchNumberValue("13205972138597109830758190748937102794")
* = 1.320597213859711E37 (java.lang.Double)
* </pre>
*
* 本方法不涉及正则表达式,同时未避免生成异常的巨大系统消耗,通过遍历字符串每
* 一个字符来判断其是否符合十进制数值格式,格式不符则直接返回
* <code>null</code> 。如果格式符合,浮点数按 {@link Double} 识别,整数按
* {@link Long} 识别。如果数值范围符合 {@link Integer} ,则转换。
*
* @see StringTool#removeChar(String, char)
* @param numStr 准备提取数值的字符串
* @return 传入字符串按十进制理解的数值对象,其类型有可能为
* <code>Long</code> 、 <code>Integer</code> 或者 <code>Double</code>。
* @exception NumberFormatException 当字符串是整数但超过了
* {@link Long#MIN_VALUE} - {@link Long#MAX_VALUE} 范围同时其位数并不大于 20,
* 或者字符串是浮点数 但超过了
* {@link Double#MIN_VALUE} - {@link Double#MAX_VALUE} 范围。
*/
static public Number parseNumber(String numStr)
{
if (numStr == null || (numStr = numStr.trim()).length() ==
0)
return null;
final StringBuilder numBuilder =
new StringBuilder();
boolean doubleFlag = false;
final int length = numStr.length();
char numChar;
for (int index =
0; index != length; index++)
{
numChar = numStr.charAt(index);
if (numChar > 57)
return null;
switch (StringTool.charType[numChar])
{
// 在之前没有小数点的情况下出现小数点,记录,同时认为此字符串是浮点数
case 3:
if (doubleFlag || index == length -
1) return null;
doubleFlag = true;
// 此处通过
// 如果是数字,认为此字符串还是数值,检查下一个字符
case 4: numBuilder.append(numChar);
// 此处通过
// 如果是空格,直接检查下一个字符
case 1:
continue;
// 如果是负号,又不是首位,则按非数值字符串进行返回
case 2:
if (index == 0)
{
numBuilder.append(numChar);
continue;
}
// 此处通过
// 如果字符不符合数值格式,方法按非数值字符串进行返回
case 0:
return null;
}
}
if (doubleFlag || length >
20)
return Double.valueOf(numBuilder.toString());
// 非浮点数情况,如果数值在整数范围内,则按整数返回。否则按长整数返回。
final long num = Long.parseLong(numBuilder.toString());
final int finalNum = (int) num;
if (finalNum != num) return num;
return finalNum;
}
/**
* <b>字符类型数组</b><br/>
* 为字符串抽取数值含义提供的字符类型获取器。通过将字符本身作为此数组下标获取对应
* 类型。类型用整数表示,含义如下。<br/>
* 1 为空白间隔,对应 <code>' '</code> 和 <code>'\t'</code><br/>
* 2 为负号,对应 <code>'-'</code><br/>
* 3 为小数点,对应 <code>'.'</code><br/>
* 4 为数字,对应 <code>'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'</code>
*/
static private
int[] charType = {
0,0,0,0,0,
0,0,0,0,1,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,1,0,0,
0,0,0,0,0,
0,0,0,0,0,
2,3,0,4,4,
4,4,4,4,4,
4,4,4
};
相关文章推荐
- 【综述】Spads 出品字符串高效提取数值方法 Shane 末日圣诞奉献 推荐
- Spads 出品字符串高效提取数值方法 Shane 末日圣诞奉献
- 【功能】Spads 出品字符串高效提取数值方法 Shane 末日圣诞奉献
- 【性能】甲 Spads 出品字符串高效提取数值方法 Shane 末日圣诞奉献 推荐
- 【性能】乙 Spads 出品字符串高效提取数值方法 Shane 末日圣诞奉献
- 【程序】Spads 出品字符串高效提取数值方法 Shane 末日圣诞奉献
- 利用sed从文本中提取字符串的方法
- C#中字符串的格式化及转换成数值的方法
- OC中字符串和数值的方法与使用实例解析
- mysql字符串按数值排序方法
- sqlserver,一个自定义函数(提取字符串中的数值,包含0-9和‘.’)
- 【字符串操作之】返回两个数值之间的字符串。→→substring方法
- 关于Java从字符串中提取数字的方法
- 高效中英文字符串截取方法[不用普遍的正则表达式方法]
- C# DataTable中Compute方法用法集锦(数值/字符串/运算符/表等操作)
- 流编辑器sed使用总结及利用sed从文本中提取字符串的方法
- JS中substring()方法(用于提取字符串中介于两个指定下标之间的字符)
- NSString 字符串中提取目标字段 & 截取的三种方法
- 一个高效的截取字符串长度方法
- C#中高效的截取字符串长度的方法