在JavaScript中将整个字符串转换为整数

7

我最近遇到了一段非常类似于此的代码:

var nHours = parseInt(txtHours);
if( isNaN(nHours))  // Do something
else // Do something else with the value

这段代码的开发者认为nHours应该是一个整数,它要么与txtHours完全匹配,要么是NaN。这个假设存在几个问题。
首先,开发者没有加上基数参数,这意味着输入"09"会导致值为0而不是9。可以通过像这样添加基数来解决这个问题:
var nHours = parseInt(txtHours,10);
if( isNaN(nHours))  // Do something
else // Do something else with the value

接下来,输入"1.5"将导致一个值为1而不是开发人员预期的NaN,因为1.5不是整数。同样,值"1a"将导致一个值为1而不是NaN
所有这些问题都有一定的可理解性,因为这是将字符串转换为整数的最常见示例之一,大多数地方都没有讨论这些情况。
无论如何,这让我想到了我不知道任何内置的方法来获得这样的整数。有Number(txtHours)(或+txtHours),它更接近,但接受非整数数字,并将null""视为0而不是NaN
为了帮助开发人员,我提供了以下函数:
function ConvertToInteger(text)
{
    var number = Math.floor(+text);
    return text && number == text ? number : NaN;
}

这似乎涵盖了以上所有问题。有人知道这种技术存在什么问题,或者可能有一种更简单的方法来获得相同的结果吗?


可能重复的[https://dev59.com/H3VC5IYBdhLWcg3w-WSs]。 - subosito
1
此外,有一个约定,构造函数的名称应该大写,而常规函数的名称不应该大写。我建议遵循这个约定,使用小写名称,如convertToIntegertoInteger。除此之外,这个函数看起来对我来说非常稳定。 - Šime Vidas
1
ConvertToInteger(true) 返回 1,这不是期望的行为,我想。 - Šime Vidas
似乎在这些值进入系统时进行一些输入验证可能是一个有价值的方法。 - Sean Reifschneider
Math.floor(+x)处理边界情况与(x | 0)相同,但是向零舍入的语义似乎比向下舍入更直观(对于熟悉C/Java浮点数转整型的人来说)。 - Mike Samuel
显示剩余2条评论
4个回答

4

这是我想到的内容:

function integer(x) {
    if (typeof x !== "number" && typeof x !== "string" || x === "") {
        return NaN;
    } else {
        x = Number(x);
        return x === Math.floor(x) ? x : NaN;
    }
}

(Note: 我更新了这个函数以防止空白字符串。见下方。)
这个想法是仅接受类型为数字或字符串(但不包括空字符串)的参数。然后进行数字转换(在这种情况下是字符串),最后将其值与floor()的值进行比较,确定该数字是否为整数。
integer(); // NaN
integer(""); // NaN
integer(null); // NaN
integer(true); // NaN
integer(false); // NaN
integer("1a"); // NaN
integer("1.3"); // NaN
integer(1.3); // NaN    
integer(7); // 7

然而,在这里“误用”了NaN值,因为浮点数和表示浮点数的字符串会导致NaN,而这在技术上并不正确。

此外,请注意由于字符串转换为数字的方式,字符串参数可能具有尾随或前导空格或前导零:

integer("   3   "); // 3    
integer("0003"); // 3

另一种方法...

如果输入值是字符串,您可以使用正则表达式。 这个正则表达式:/^\s*(\+|-)?\d+\s*$/将匹配代表整数的字符串。

更新的函数!

function integer(x) {
    if ( typeof x === "string" && /^\s*(\+|-)?\d+\s*$/.test(x) ) {
        x = Number(x);
    }
    if ( typeof x === "number" ) {
        return x === Math.floor(x) ? x : NaN;
    }
    return NaN;
}

这个版本的integer()函数更加严格,只允许符合某种模式(通过正则表达式测试)的字符串。它产生与其他integer()函数相同的结果,但还会忽略所有空白字符串(如@CMS所指出的)。

再次更新!

我注意到了@Zecc的答案并简化了代码... 我想这也可以运行:

function integer(x) {
    if( /^\s*(\+|-)?\d+\s*$/.test(String(x)) ){
        return parseInt(x, 10);
    }
    return Number.NaN;
}  

可能不是最快的解决方案(就性能而言),但我喜欢它的简洁 :)


我知道使用NaN是不正确的,但它似乎是表示非整数的一种好方法。毕竟,没有NaI。我可以做几件事情,包括使用null、undefined、对象或多个函数,但NaN是原始代码正在寻找的内容,而且似乎足够清晰,可以继续使用它。 - drs9222
@drs9222 是的,NaN值对于这种情况已经足够好了。特别是因为有一个isNaN()函数,所以你可以轻松地测试返回值来确定输入是否为有效整数。x = integer(input); if ( !isNaN(x) ) { /* 处理输入 */ } else { /* 提醒用户输入无效 */ } - Šime Vidas
我刚想起来一件事:typeof new Number(8) === "object"typeof new String("123") === "object",不知为何。所以这些类型检查可能会带来一些麻烦。 - Zecc
另一方面,fakeNumber = { toString: function(){return "7";} }将很乐意遵守integer的最后一个版本。但我认为这不是问题。 :) - Zecc
@Zecc String(x) 和 Number(x) 将转换为原始类型。new String(x) 和 new Number(x) 返回对象。这是在规范中定义的。 - Šime Vidas
显示剩余3条评论

1

这是我的尝试:

function integer(x) {
    var n = parseFloat(x); // No need to check typeof x; parseFloat does it for us
    if(!isNaN(n) && /^\s*(\+|-)?\d+\s*$/.test(String(x))){
        return n;
    }
    return Number.NaN;
}

我必须感谢Šime Vidas提供的正则表达式,尽管我也能自己实现。

编辑:我不知道有一个全局的NaN。我一直使用Number.NaN
活到老学到老。


1
实际上,使用Number.NaN而不是NaN是一个明智的选择,因为全局变量NaN可以被任何其他值覆盖(例如 var NaN = "foo"),而Number.NaN属性则不能。 - Šime Vidas

1

我的解决方案涉及一些便宜的技巧。它基于Javascript中的位运算符将其操作数转换为整数的事实。

我不太确定表示整数的字符串是否有效,因此这里提供了两种不同的解决方案。

function integer (number) { 
  return ~~number == number ? ~~number : NaN; 
}

function integer (number) {
  return ~~number === number ? ~~number : NaN;
}

第一个代码可以处理字符串或整数,但第二个不能。 按位非(~)操作符将把其操作数转换为整数。 该方法无法处理超过32位整数表示范围(-2147483647 .. 2147483647)的大整数。

-1

你可以先将字符串转换为整数,然后再转换回字符串。接着检查第一和第二个字符串是否相匹配。

编辑: 我所指的例子如下:

function cs (stringInt) {
    var trimmed = stringInt.trim();     // trim original string
    var num = parseInt(trimmed, 10);    // convert string to integer
    newString = num + "";               // convert newly created integer back to string
    console.log(newString);             // (works in at least Firefox and Chrome) check what's new string like
    return (newString == trimmed);      // if they are identical, you can be sure that original string is an integer
}

如果您输入的字符串确实是一个整数,此函数将返回 true。如果您不想要修剪,则可以进行修改。使用前导零将导致失败,但是您可以在本函数中通过去除它们来解决此问题。这样,您就不需要使用 NaN 或正则表达式来验证字符串化的整数的有效性,可以轻松地检查其有效性。


@darioo 如何将字符串转换为整数?有多种方法。 - Šime Vidas
@Šime Vidas:我更新了我的回答。我认为parseInt仍然是将字符串转换为整数的最佳方法。 - darioo
我怀疑你是有意这样设计的,但是如果输入除了字符串以外的任何东西,包括整数,你的示例将会失败。它也不能返回实际的整数供使用。 - drs9222
@drs9222:好吧,你确实要求一个能够转换字符串的东西,而不是其他任何东西。你不必完全按照这个函数编写,可以根据自己的需要进行修改。但是,你可以使用它来检查输入的字符串是否真的是整数,然后使用parseInt进行实际转换。我编写的更像是一个实用函数。 - darioo
我理解了,我刚刚重新阅读了我的原始问题,你是对的,我确实说了字符串。然而,我还特别提到了null。我想我被我对示例运行的测试和其他答案所迷惑了,它们会接受任何输入。 - drs9222
@drs9222:嗯,将""null作为特殊情况添加到这些函数中是微不足道的。问题在于,您想要一些特殊行为,例如将""null转换为0。根据我对Javascript的理解,没有通用的函数可以完全满足您的要求,因此您必须自己编写代码。如果您希望得到没有歧义的答案,您应该更加精确地说明您的问题。 - darioo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接