int.TryParse가 실제로 작동하는 방식


80

int.TryParse메서드 구현을 찾았는데 실제로 어떻게 작동하는지 찾지 못했습니다. 나는 string그것이 숫자 값인지 여부 를 알아야 하지만 지금은 그것을 변환하고 싶지 않습니다.

그래서 나는 단지 필요 bool에서 결과를 int.TryParse. 따라서 질문은 다음과 같습니다.

  1. bool결과 만 제공 할 수있는 기능이 있나요?

  1. int.TryParse실제로 어떻게 작동 하는지 알고 싶습니다 ( try ... catch입력의 문자를 반복하거나 내부가 string있습니까)?

1. 아니요, 없습니다. 을 사용할 수 Convert.ToInt32()있지만 문자열을 구문 분석 할 수없는 경우 예외가 발생합니다. 2. 그것은 문자열을 반복하는 것입니다,하지만 빠르게에서 예외를 잡는 것보다 이후 아마, 어떤 예외를 잡을 것Convert.ToInt32()
Nolonar

정규식 ^ \ d + $를 사용할 수 있습니다. 또는 IsDigit에 대해 각 문자를 평가합니다.
paparazzo

답변:


103

bool결과 만 필요하면 반환 값을 사용하고 out매개 변수를 무시하십시오 .

bool successfullyParsed = int.TryParse(str, out ignoreMe);
if (successfullyParsed){
    // ...
}

편집 : 그동안 원본 소스 코드를 볼 수도 있습니다 .

System.Int32.TryParse


실제로 어떻게 구현되는지 알고 싶다면 ILSpy.NET 코드를 디 컴파일하는 데 사용 하고 있습니다.

결과는 다음과 같습니다.

// int
/// <summary>Converts the string representation of a number to its 32-bit signed integer equivalent. A return value indicates whether the operation succeeded.</summary>
/// <returns>true if s was converted successfully; otherwise, false.</returns>
/// <param name="s">A string containing a number to convert. </param>
/// <param name="result">When this method returns, contains the 32-bit signed integer value equivalent to the number contained in s, if the conversion succeeded, or zero if the conversion failed. The conversion fails if the s parameter is null, is not of the correct format, or represents a number less than <see cref="F:System.Int32.MinValue"></see> or greater than <see cref="F:System.Int32.MaxValue"></see>. This parameter is passed uninitialized. </param>
/// <filterpriority>1</filterpriority>
public static bool TryParse(string s, out int result)
{
    return Number.TryParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
}


// System.Number
internal unsafe static bool TryParseInt32(string s, NumberStyles style, NumberFormatInfo info, out int result)
{
    byte* stackBuffer = stackalloc byte[1 * 114 / 1];
    Number.NumberBuffer numberBuffer = new Number.NumberBuffer(stackBuffer);
    result = 0;
    if (!Number.TryStringToNumber(s, style, ref numberBuffer, info, false))
    {
        return false;
    }
    if ((style & NumberStyles.AllowHexSpecifier) != NumberStyles.None)
    {
        if (!Number.HexNumberToInt32(ref numberBuffer, ref result))
        {
            return false;
        }
    }
    else
    {
        if (!Number.NumberToInt32(ref numberBuffer, ref result))
        {
            return false;
        }
    }
    return true;
}

그리고 아니요, Try-Catchs도로에서 아무것도 볼 수 없습니다 .

// System.Number
private unsafe static bool TryStringToNumber(string str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
{
    if (str == null)
    {
        return false;
    }
    fixed (char* ptr = str)
    {
        char* ptr2 = ptr;
        if (!Number.ParseNumber(ref ptr2, options, ref number, numfmt, parseDecimal) || ((ptr2 - ptr / 2) / 2 < str.Length && !Number.TrailingZeros(str, (ptr2 - ptr / 2) / 2)))
        {
            return false;
        }
    }
    return true;
}

// System.Number
private unsafe static bool ParseNumber(ref char* str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
{
    number.scale = 0;
    number.sign = false;
    string text = null;
    string text2 = null;
    string str2 = null;
    string str3 = null;
    bool flag = false;
    string str4;
    string str5;
    if ((options & NumberStyles.AllowCurrencySymbol) != NumberStyles.None)
    {
        text = numfmt.CurrencySymbol;
        if (numfmt.ansiCurrencySymbol != null)
        {
            text2 = numfmt.ansiCurrencySymbol;
        }
        str2 = numfmt.NumberDecimalSeparator;
        str3 = numfmt.NumberGroupSeparator;
        str4 = numfmt.CurrencyDecimalSeparator;
        str5 = numfmt.CurrencyGroupSeparator;
        flag = true;
    }
    else
    {
        str4 = numfmt.NumberDecimalSeparator;
        str5 = numfmt.NumberGroupSeparator;
    }
    int num = 0;
    char* ptr = str;
    char c = *ptr;
    while (true)
    {
        if (!Number.IsWhite(c) || (options & NumberStyles.AllowLeadingWhite) == NumberStyles.None || ((num & 1) != 0 && ((num & 1) == 0 || ((num & 32) == 0 && numfmt.numberNegativePattern != 2))))
        {
            bool flag2;
            char* ptr2;
            if ((flag2 = ((options & NumberStyles.AllowLeadingSign) != NumberStyles.None && (num & 1) == 0)) && (ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
            {
                num |= 1;
                ptr = ptr2 - (IntPtr)2 / 2;
            }
            else
            {
                if (flag2 && (ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                {
                    num |= 1;
                    number.sign = true;
                    ptr = ptr2 - (IntPtr)2 / 2;
                }
                else
                {
                    if (c == '(' && (options & NumberStyles.AllowParentheses) != NumberStyles.None && (num & 1) == 0)
                    {
                        num |= 3;
                        number.sign = true;
                    }
                    else
                    {
                        if ((text == null || (ptr2 = Number.MatchChars(ptr, text)) == null) && (text2 == null || (ptr2 = Number.MatchChars(ptr, text2)) == null))
                        {
                            break;
                        }
                        num |= 32;
                        text = null;
                        text2 = null;
                        ptr = ptr2 - (IntPtr)2 / 2;
                    }
                }
            }
        }
        c = *(ptr += (IntPtr)2 / 2);
    }
    int num2 = 0;
    int num3 = 0;
    while (true)
    {
        if ((c >= '0' && c <= '9') || ((options & NumberStyles.AllowHexSpecifier) != NumberStyles.None && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))))
        {
            num |= 4;
            if (c != '0' || (num & 8) != 0)
            {
                if (num2 < 50)
                {
                    number.digits[(IntPtr)(num2++)] = c;
                    if (c != '0' || parseDecimal)
                    {
                        num3 = num2;
                    }
                }
                if ((num & 16) == 0)
                {
                    number.scale++;
                }
                num |= 8;
            }
            else
            {
                if ((num & 16) != 0)
                {
                    number.scale--;
                }
            }
        }
        else
        {
            char* ptr2;
            if ((options & NumberStyles.AllowDecimalPoint) != NumberStyles.None && (num & 16) == 0 && ((ptr2 = Number.MatchChars(ptr, str4)) != null || (flag && (num & 32) == 0 && (ptr2 = Number.MatchChars(ptr, str2)) != null)))
            {
                num |= 16;
                ptr = ptr2 - (IntPtr)2 / 2;
            }
            else
            {
                if ((options & NumberStyles.AllowThousands) == NumberStyles.None || (num & 4) == 0 || (num & 16) != 0 || ((ptr2 = Number.MatchChars(ptr, str5)) == null && (!flag || (num & 32) != 0 || (ptr2 = Number.MatchChars(ptr, str3)) == null)))
                {
                    break;
                }
                ptr = ptr2 - (IntPtr)2 / 2;
            }
        }
        c = *(ptr += (IntPtr)2 / 2);
    }
    bool flag3 = false;
    number.precision = num3;
    number.digits[(IntPtr)num3] = '\0';
    if ((num & 4) != 0)
    {
        if ((c == 'E' || c == 'e') && (options & NumberStyles.AllowExponent) != NumberStyles.None)
        {
            char* ptr3 = ptr;
            c = *(ptr += (IntPtr)2 / 2);
            char* ptr2;
            if ((ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
            {
                c = *(ptr = ptr2);
            }
            else
            {
                if ((ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                {
                    c = *(ptr = ptr2);
                    flag3 = true;
                }
            }
            if (c >= '0' && c <= '9')
            {
                int num4 = 0;
                do
                {
                    num4 = num4 * 10 + (int)(c - '0');
                    c = *(ptr += (IntPtr)2 / 2);
                    if (num4 > 1000)
                    {
                        num4 = 9999;
                        while (c >= '0' && c <= '9')
                        {
                            c = *(ptr += (IntPtr)2 / 2);
                        }
                    }
                }
                while (c >= '0' && c <= '9');
                if (flag3)
                {
                    num4 = -num4;
                }
                number.scale += num4;
            }
            else
            {
                ptr = ptr3;
                c = *ptr;
            }
        }
        while (true)
        {
            if (!Number.IsWhite(c) || (options & NumberStyles.AllowTrailingWhite) == NumberStyles.None)
            {
                bool flag2;
                char* ptr2;
                if ((flag2 = ((options & NumberStyles.AllowTrailingSign) != NumberStyles.None && (num & 1) == 0)) && (ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
                {
                    num |= 1;
                    ptr = ptr2 - (IntPtr)2 / 2;
                }
                else
                {
                    if (flag2 && (ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                    {
                        num |= 1;
                        number.sign = true;
                        ptr = ptr2 - (IntPtr)2 / 2;
                    }
                    else
                    {
                        if (c == ')' && (num & 2) != 0)
                        {
                            num &= -3;
                        }
                        else
                        {
                            if ((text == null || (ptr2 = Number.MatchChars(ptr, text)) == null) && (text2 == null || (ptr2 = Number.MatchChars(ptr, text2)) == null))
                            {
                                break;
                            }
                            text = null;
                            text2 = null;
                            ptr = ptr2 - (IntPtr)2 / 2;
                        }
                    }
                }
            }
            c = *(ptr += (IntPtr)2 / 2);
        }
        if ((num & 2) == 0)
        {
            if ((num & 8) == 0)
            {
                if (!parseDecimal)
                {
                    number.scale = 0;
                }
                if ((num & 16) == 0)
                {
                    number.sign = false;
                }
            }
            str = ptr;
            return true;
        }
    }
    str = ptr;
    return false;
}

4
나는 더 복잡하다. :) 감사합니다!
speti43 2013 년

19

그냥 있기 때문에 int.TryParse당신에게 가치를 제공 당신이 그것을 유지할 필요가 의미하지 않는다; 당신은 이것을 아주 행복하게 할 수 있습니다 :

int temp;
if (int.TryParse(inputString, out temp))
{
    // do stuff
}

temp필요하지 않으면 완전히 무시할 수 있습니다 . 당신이 그것을 필요로한다면, 당신이 그것을 원할 때 당신을 기다리고 있습니다.

내부에 관해서는 내가 기억하는 한 문자열의 원시 바이트를 int로 읽고 결과가 유효한지 여부를 테스트합니다. 숫자가 아닌 문자를 찾는 것을 반복하는 것만 큼 간단하지 않습니다.


16

이제 C # 7.0 이상에서 다음과 같이 작성할 수 있습니다.

if (int.TryParse(inputString, out _))
{
    //do stuff
}

이것은 질문에 대한 답이 아닙니다.
테마 필드

1
밖으로 무엇을합니까?
mrid

@mrid 호출 범위의 변수가 쓰기 액세스 권한이있는 메서드 범위에 제공되도록 지정합니다. 변수가 예 경우 int someInt에 전달됩니다 int.TryParse좋아 int.TryParse(out someInt), int.TryParse에 출력을 배치 할 수 someInt는 정상 범위를 벗어난 것에도 불구하고.
timelmer 19

@themefield-게시물 본문에서 바로이 질문에 답합니다. "따라서 질문은 다음과 같습니다. 1) bool 결과 만 제공 할 수있는 기능이 있습니까?"
antiduh

13

TryParse는 한 줄로 구문 분석하거나 유효성을 검사하는 가장 좋은 방법입니다.

int nNumber = int.TryParse("InputString", out nNumber) ? nNumber : 1;

간단한 설명:

  1. nNumber는 0으로 초기화됩니다.
  2. int.TryParse () "InputString"구문 분석을 시도하고 성공하면 nNumber로 설정합니다.
  3. 짧은 경우? : int.TryParse () 결과를 확인하고 nNumber 또는 1을 기본값으로 반환합니다.

1
cannot use local variable 'nCurPage' before it is declared
Devin Burke

devin-burke에게, 맞아요. 나는 ... 오류 또는 경고없이 그것을 여러 시간을 사용
Zolfaghari

8

Regex는 속도를 위해 컴파일되므로 한 번 만들고 다시 사용하십시오.
새로운 것은 IsMatch보다 오래 걸립니다.
이것은 모든 숫자 만 확인합니다.
범위를 확인하지 않습니다.
범위를 테스트해야하는 경우 TryParse를 사용하는 것이 좋습니다.

private static Regex regexInt = new Regex("^\\d+$");
static bool CheckReg(string value)
{
    return regexInt.IsMatch(value);
}

2

이해하려면이 간단한 프로그램을 확인하십시오. int.TryParse

 class Program
 {
    static void Main()
    {
        string str = "7788";
        int num1;
        bool n = int.TryParse(str, out num1);
        Console.WriteLine(num1);
        Console.ReadLine();
    }
}

출력 : 7788

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.