判断字符串到 double/float/int/short/byte 是不是超出范围
Posted
技术标签:
【中文标题】判断字符串到 double/float/int/short/byte 是不是超出范围【英文标题】:Tell if string to double/float/int/short/byte is out of range判断字符串到 double/float/int/short/byte 是否超出范围 【发布时间】:2013-09-02 09:52:36 【问题描述】:我有以下几点:
string outOfRange = "2147483648"; // +1 over int.MaxValue
显然,如果您有除数字以外的任何内容,这将失败:
var defaultValue = 0;
int.TryParse(outOfRange, out defaultValue);
我的问题是,因为这是一个数字,当你 int.TryParse()
时它会失败,你怎么知道它失败是因为字符串超出了它存储的容器的范围?
【问题讨论】:
是否首先将其解析为更大的容量值(比如long
,或者uint
,如果你知道你只有正数)然后检查Int32.Max/MinValue
是否可行?
我想这可能是一种解决方案。也许更通用的东西适用于任何容器类型。
您可以通过使用Try-Catch
并检查异常消息而不是int.TryParse
来获得一个想法
有什么用?如果是为了验证输入,则可能没有必要,考虑到您可以在消息中覆盖它,而不会产生许多不同消息的复杂性。如果是针对您无能为力的情况,那么请改用Parse
方法来允许发生异常,也许?只是我的好奇心和观察。
我同意@GrantThomas,从用户的角度来看,他们为什么要知道int
溢出+- 20 亿?用例应确定您期望的实际输入范围,您将根据该范围编写验证,并且您还将选择适当的数据类型。
【参考方案1】:
对于这种情况,我会选择 Try/Catch
解决方案。
string outOfRange = "2147483648";
try
int.Parse(outOfRange);
catch (OverflowException oex)
catch (Exception ex)
我知道这里的大多数人会建议避免使用它,但有时我们只需要使用它(或者我们不必使用它,但这只会为我们节省大量时间)。here's 一个小帖子关于Try/Catch
的效率。
【讨论】:
【参考方案2】:可以解析成十进制再检查范围,避免try/catch
string s = "2147483648";
decimal.Parse(s) > int.MaxValue;
【讨论】:
【参考方案3】:我会尝试解析,如果失败,然后尝试解析更高容量的值。如果更高的容量值通过解析,那么您就知道它超出了范围。如果它也失败了,那就是错误的输入。
string outOfRange = "2147483648"; // +1 over int.MaxValue
int result;
if (!Int32.TryParse(outOfRange, out result))
long rangeChecker;
if (Int64.TryParse(outOfRange, out rangeChecker))
//out of range
else
//bad format
不幸的是,我认为没有办法对任何类型通用地执行此操作。您必须为所有类型编写一个实现。例如,Int64
做什么?也许改用BigInteger
:
string outOfRange = "9223372036854775808"; // +1 over Int64.MaxValue
long result;
if (!Int64.TryParse(outOfRange, out result))
BigInteger rangeChecker;
if (BigInteger.TryParse(outOfRange, out rangeChecker))
//out of range
else
//bad format
编辑:double
浮点值可能会更有趣,因为 AFAIK,没有“BigDecimal”,您可能还必须考虑在极端情况下接近 0 的值(不确定那)。可能您可以对BigInteger
检查进行变体,但您可能还必须考虑小数点(可能一个简单的正则表达式最好只有数字,一个可选的负号,并且最多只有一个 /em> 小数点)。如果有任何小数点,您必须将它们截断并简单地检查字符串的整数部分。
EDITx2:这也是检查double
值的一个非常丑陋的实现:
// +bajillion over Double.MaxValue
string outOfRange = "90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.1";
double result;
if (!Double.TryParse(outOfRange, out result))
string bigIntegerInput = outOfRange;
if (!Regex.IsMatch(bigIntegerInput, @"^-?[0-9]\d*(\.\d+)?$"))
//bad format
int decimalIndex = bigIntegerInput.IndexOf('.');
if (decimalIndex > -1)
bigIntegerInput = bigIntegerInput.Substring(0, decimalIndex);
BigInteger rangeChecker;
if (BigInteger.TryParse(bigIntegerInput, out rangeChecker))
//out of range
else
//bad format
但老实说,在这一点上,我认为我们刚刚走到了尽头。除非您有一些真正的性能瓶颈,或者您的应用程序经常输入超出范围的值,否则您最好只在this answer 中发生的奇怪时间捕获它们,或者更简单,将 regex 应用于输入。在我的最后一个示例中,无论如何,我也可能在执行正则表达式后退出(但我不知道TryParse
实现是否更宽松,允许指数/科学符号。如果是这样,正则表达式也必须涵盖这些)
【讨论】:
【参考方案4】:string outOfRange = "2147483648"; // +1 over int.MaxValue
int value;
if(! int.TryParse(outOfRange, out value))
try
int.Parse(defaultValue);
catch(OverflowException e)
// was overflow
catch(Exception e)
// was other reason
假设数量过大的情况很少,抛出和捕获异常的开销可能是可以容忍的,因为正常情况使用更快的TryParse
方法处理而不涉及异常。
这对于其他数字数据类型(如浮点数、...
【讨论】:
不要对控制流使用异常。 您可以改用Int64.TryParse
;如果它通过了,你就知道它超出了范围。如果它失败了,那么你就知道这是错误的输入。
@ChrisSinclair 但最初的问题还想知道长、双精度等的解决方案。
@It'sNotALie。在有效数字的标准情况下,没有例外。我认为溢出的情况至少部分是例外的。并且首先检查所有有效字符串的解决方案并不简单,特别是如果您想按照原始帖子的要求将其用于双打。因此,我在这里要说的是,使用异常是不使用异常进行控制流的规则的例外。【参考方案5】:
您可以尝试使用BigInteger
进行解析。
BigInteger bigInt;
bool isAnOutOfRangeInt = BigInteger.TryParse(input, out bigInt)
&& (bigInt > int.MaxValue || bigInt < int.MinValue);
// if you care to have the value as an int:
if (!isAnOutOfRangeInt)
int intValue = (int)bigInt;
【讨论】:
按照原帖的要求,您将如何将其用于double
s 而不是int
s?【参考方案6】:
使用普通的Parse
而不是TryParse
。然后在 try/catch 中使用它,因为它会给你适当的异常。有关详细信息,请参阅:http://msdn.microsoft.com/en-us/library/b3h1hf19.aspx。您正在寻找的例外是OverflowException。
【讨论】:
既然可以使用TryParse
的返回值,为什么还要使用异常来控制流?
TryParse
返回一个bool
,这与从Parse
中获取许多不同的异常不可比。【参考方案7】:
我会考虑使用System.Convert.ToInt32(String) 作为转换事物的机制;即因为 OverflowException 已经为你实现了。
这很方便,因为你可以做一些简单的事情,比如
try
result = Convert.ToInt32(value);
Console.WriteLine("Converted the 0 value '1' to the 2 value 3.",
value.GetType().Name, value, result.GetType().Name, result);
catch (OverflowException)
Console.WriteLine("0 is outside the range of the Int32 type.", value);
catch (FormatException)
Console.WriteLine("The 0 value '1' is not in a recognizable format.",
value.GetType().Name, value);
并且逻辑已经是标准系统库的一部分。
【讨论】:
这不涉及双精度/浮点数。 Convert.ToDouble(String) 和 Convert.ToFloat(String) 当然可以。它们已经被 MSDN 实现了。 我将您的“作为转换事物的机制”解释为上面的代码也可用于转换双精度和浮点数。如果您的代码是部分解决问题的示例,而其他代码(例如 double/float)所需的其他代码,则我的上述评论不适用。【参考方案8】:直接的方法是使用Int32.Parse(string s) 并捕获OverflowException
;
溢出异常 s 表示小于 MinValue 或大于 MaxValue 的数字。
【讨论】:
@It'sNotALie。一般来说,我会避免使用它们进行这种操作,但在这种情况下,写一个替换并不是直接的。如果您涉及IFormatProvider
,则更是如此。以上是关于判断字符串到 double/float/int/short/byte 是不是超出范围的主要内容,如果未能解决你的问题,请参考以下文章
用Shell编程,判断文件是否字符设备文件,如果是将其拷贝到/dev目录下
用While MSComm1.InBufferCount = 0只能判断接收到字符,不能判断接收是不是完毕,如何更改这条语句?