2010-11-12 7 views
7

Niedawno wpadł na kawałek kodu bardzo podobne do tego:Konwersja cały łańcuch na liczbę całkowitą w JavaScript

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

Deweloper, który napisał ten kod był pod wrażeniem, że nHours albo by być liczbą całkowitą który dokładnie pasował do txtHours lub . Jest kilka rzeczy nie tak z tym założeniem.

Po pierwsze, deweloper po lewej stronie argumentu radix, co oznacza wprowadzenie "09", spowoduje, że zamiast 9 pojawi się wartość 0. Ten problem może być rozwiązany poprzez dodanie przelicznika w taki sposób:

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

Następnie wejście "1.5" spowoduje wartości 1 zamiast NaN który nie ma co oczekiwać od 1.5 deweloper nie jest liczbą całkowitą. Podobnie wartość "1a" spowoduje wyświetlenie wartości 1 zamiast NaN.

Wszystkie te problemy są dość zrozumiałe, ponieważ jest to jeden z najczęstszych przykładów konwersji ciągu na liczbę całkowitą, a większość miejsc nie omawia tych przypadków.

W każdym razie dało mi to do myślenia, że ​​nie jestem świadomy żadnych wbudowane w sposób, aby uzyskać taką liczbę całkowitą. Istnieje Number(txtHours) (lub +txtHours), który jest bliżej, ale akceptuje liczby niecałkowite i traktuje null i "" jako 0 zamiast NaN.

Aby pomóc programiście z I, pod warunkiem następującą funkcję:

function ConvertToInteger(text) 
{ 
    var number = Math.floor(+text); 
    return text && number == text ? number : NaN; 
} 

to wydaje się obejmować wszystkie powyższe problemy. Czy ktoś wie o czymś złym w tej technice, czy może prostszy sposób uzyskania tych samych wyników?

+0

Prawdopodobnie powielone [http://stackoverflow.com/questions/131406/what-is-the-best-metod-to-convert-to-an-integer-in-javascript](http://stackoverflow.com/questions/131406/what-is-the-best-method-to-convert-to-an-integer-in-javascript) – subosito

+0

'Number (txtHours)' zamiast 'number (txtHours)' –

+1

Istnieje również konwencja, w której nazwy funkcji konstruktora są pisane wielką literą, a zwykłe nazwy funkcji nie. Polecam trzymać się tej konwencji, używając małej litery, na przykład 'convertToInteger' lub' toInteger'. Poza tym funkcja wygląda na całkiem solidną. –

Odpowiedz

3

Tutaj, to co wymyśliłem:

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

(Uwaga: Po zaktualizowaniu tej funkcji do saveguard przeciwko ciągi białych przestrzeni Patrz niżej.).

Chodzi o to, aby akceptować tylko argumenty typem jest Number lub String (ale nie pusta wartość ciągu). Następnie następuje konwersja do liczby (w przypadku, gdy był to ciąg znaków), a na końcu jego wartość jest porównywana z wartością floor() w celu ustalenia, czy liczba jest liczbą całkowitą, czy nie.

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 

Jednakże wartość NaN jest „nadużywane” tutaj, ponieważ pływaki oraz ciągi reprezentujące pływaków skutkować NaN, a to nie jest technicznie prawdziwe.

Należy również pamiętać, że ze względu na sposób ciągi są konwertowane na liczby, argument ciąg mogło spływu lub prowadzących white-space lub prowadzących zer:

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

inne podejście ...

Możesz użyć wyrażenia regularnego, jeśli wartość wejściowa jest łańcuchem znaków. To wyrażenie regularne: /^\s*(\+|-)?\d+\s*$/ dopasuje ciągi reprezentujące liczby całkowite.

ZAKTUALIZOWANA FUNKCJA!

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; 
} 

Ta wersja całkowitej() jest bardziej rygorystyczne, ponieważ umożliwia jedynie ciągi realizujących określony wzór (który jest badany wyrażenia regularnego). Wywołuje on takie same wyniki, jak inna funkcja liczby całkowitej(), z tym wyjątkiem, że dodatkowo pomija wszystkie ciągi znaków odstępu białkowego (jak wskazano w @CMS).

Zaktualizowano ponownie!

zauważyłem @ odpowiedź Zecc i uproszczony kod nieco ... Chyba to działa, TOO:

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

To probaly nie jest najszybszym rozwiązaniem (pod względem wydajności), ale Podoba mi się jego prostota :)

+0

@CMS Oh, co za bałagan :) Sprawdzenie regexp może rozwiązać ten problem. –

+0

Jestem świadomy, że używanie NaN jest niewłaściwe, ale wydaje się tak dobry, jak każdy inny sposób reprezentowania nie liczbą całkowitą. W końcu nie ma NaI. Jest kilka rzeczy, które mogłem zrobić, w tym null, undefined, obiekt lub wiele funkcji, ale NaN było tym, czego szukał oryginalny kod i wydawało się, że jest wystarczająco jasne, by iść naprzód. – drs9222

+0

Moją pierwszą myślą, kiedy zobaczyłem to było użycie zwykłego wyrażenia, ale wydawało mi się, że to przesada dla czegoś, co moim zdaniem powinno być bardzo proste. Gdybyśmy chcieli, moglibyśmy tego uniknąć poprzez przycięcie wejścia, jeśli jest to ciąg. – drs9222

-1

Najpierw można przekonwertować ciąg na liczbę całkowitą, a następnie ponownie na łańcuch. Następnie sprawdź, czy pierwsze i drugie ciągi pasują do siebie.

Edit: przykładem tego, co mam na myśli:

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 
} 

Ta funkcja zwróci true, jeśli ciąg znaków można umieścić w naprawdę jest liczbą całkowitą. Można go zmodyfikować, jeśli nie chcesz przycinać. Używanie wiodących zer nie powiedzie się, ale jeszcze raz możesz się ich pozbyć w tej funkcji, jeśli chcesz. W ten sposób nie musisz się męczyć z wersją NaN lub wyrażeniem regularnym, możesz łatwo sprawdzić poprawność swojej szumiastej liczby całkowitej.

+0

@darioo Konwertuj ciąg na liczbę całkowitą ... jak? Istnieją różne metody. –

+0

@ Šime Vidas: Zaktualizowałem swoją odpowiedź. Powiedziałbym, że parseInt nadal jest najlepszym sposobem na konwersję ciągu na liczbę całkowitą. – darioo

+0

Podejrzewam, że zrobiłeś to według projektu, ale twój przykład się nie powiedzie, jeśli jako dane wejściowe zostanie użyte coś innego niż ciąg, łącznie z liczbą całkowitą. Nie zwraca również rzeczywistej liczby całkowitej do użycia. – drs9222

1

Oto moja próba:

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; 
} 

muszę kredyt Šime Vidas dla regex, choć chciałbym się tam dostać.

Edytuj: Nie zdawałem sobie sprawy, że globalna jest NaN. Zawsze używałem Number.NaN.
Żyj i ucz się.

+1

Właściwie użycie Number.NaN zamiast NaN jest mądrym wyborem, ponieważ globalna zmienna NaN może zostać zastąpiona dowolną inną wartością (var NaN = "foo"), a właściwość Number.NaN nie może. –

1

Moje rozwiązanie wiąże się z tanią sztuczką. Opiera się na fakcie, że operatory bitowe w JavaScript konwertują swoje operandy na liczby całkowite.

Nie byłem do końca pewien, czy łańcuchy reprezentujące liczby całkowite powinny działać, więc tutaj są dwa różne rozwiązania.

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

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

Pierwszy będzie działał z obie liczby całkowite jako ciągi, a drugi nie. Bitowy operator not (~) zamieni jego operand na liczbę całkowitą. Ta metoda kończy się niepowodzeniem dla liczb całkowitych większych, które nie mogą być reprezentowane przez 32-bitową reprezentację liczb całkowitych (-2147483647 .. 2147483647).