Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/301.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C语言中StringToInt函数的最佳解#_C# - Fatal编程技术网

C# C语言中StringToInt函数的最佳解#

C# C语言中StringToInt函数的最佳解#,c#,C#,在上周的一次工作面试中,我被要求在白板上执行StringToInt/Int.parse函数,虽然效果不太好,但我还是想出了一些解决方案。后来回到家里,我在视觉研究中做了一个,我想知道是否有比下面我的更好的解决方案 除了检查字符串是否只包含数字外,没有进行任何其他错误处理 private int StrToInt(string tmpString) { int tmpResult = 0; System.Text.Encoding asci

在上周的一次工作面试中,我被要求在白板上执行StringToInt/Int.parse函数,虽然效果不太好,但我还是想出了一些解决方案。后来回到家里,我在视觉研究中做了一个,我想知道是否有比下面我的更好的解决方案

除了检查字符串是否只包含数字外,没有进行任何其他错误处理

        private int StrToInt(string tmpString)
    {
        int tmpResult = 0;

        System.Text.Encoding ascii = System.Text.Encoding.ASCII;
        byte[] tmpByte = ascii.GetBytes(tmpString);

        for (int i = 0; i <= tmpString.Length-1; i++)
        {
            // Check whatever the Character is an valid digit
            if (tmpByte[i] > 47 && tmpByte[i] <= 58)
                // Here I'm using the lenght-1 of the string to set the power and multiply this to the value
                tmpResult += (tmpByte[i] - 48) * ((int)Math.Pow(10, (tmpString.Length-i)-1));
            else
                throw new Exception("Non valid character in string");

        } 

        return tmpResult;
    }
private int strotint(字符串tmpString)
{
int-tmpResult=0;
System.Text.Encoding ascii=System.Text.Encoding.ascii;
字节[]tmpByte=ascii.GetBytes(tmpString);

对于(int i=0;i 47&&tmpByte[i]我认为您的解决方案是合理的,但我不做math.pow,而是做:

tmpResult = 10 * tmpResult + (tmpByte[i] - 48);
另外,根据tmpByte的长度而不是tmpString来检查长度。这通常并不重要,但在检查另一个数组的长度时循环一个数组是很奇怪的


而且,您可以用foreach语句替换for循环。

转换为字节数组是不必要的,因为字符串已经是
char
s的数组。此外,应该避免使用像
48
这样的幻数,而使用像
'0'
这样的可读常量。我会这样做:

int result = 0;
for (int i = str.Length - 1, factor = 1; i >= 0; i--, factor *= 10)
    result += (str[i] - '0') * factor;

对于每个字符(从末尾开始),将其数值乘以正确的10次方,然后将其添加到结果中。10次方是通过重复将其乘以10来计算的,而不是不必要地使用
Math。Pow

我将采用相反的方法

public int? ToInt(this string mightBeInt)
{
    int convertedInt;
    if (int.TryParse(mightBeInt, out convertedInt))
    {
        return convertedInt;
    }
    return null;
}
在被告知这不是问题的重点之后,我认为这个问题测试的是C编码技能,而不是C#。我进一步认为,在.NET中,将字符串作为字符数组来处理是一个非常坏的习惯,因为字符串是unicode,在任何可能全球化的应用程序中,对字符表示做出任何假设tions迟早会给您带来麻烦。此外,框架已经提供了一种转换方法,它将比开发人员在如此匆忙中扔掉的任何东西都更加高效和可靠。重新发明框架功能总是一个坏主意

然后我会指出,通过编写一个扩展方法,我已经为string类创建了一个非常有用的扩展,我将在生产代码中实际使用它

如果那场争论让我失去了工作,我可能无论如何都不想在那里工作


编辑:正如一些人指出的,我错过了TryParse.Fixed中的“out”关键字。

我同意Cyclon Cat,他们可能希望有人能够利用现有的功能。 但是我会写一些不同的方法

public int? ToInt(this string mightBeInt)
{
    int number = 0;
    if (Int32.TryParse(mightBeInt, out number))
        return number;
    return null;
}

Int32.TryParse不允许将属性作为out参数提供。

仅仅因为我喜欢Linq:

string t = "1234";
var result = t.Select((c, i) => (c - '0') * Math.Pow(10, t.Length - i - 1)).Sum();

如果您想要一个使用实现的简单非框架,那么:

"1234".Aggregate(0, (s,c)=>  c-'0'+10*s)
…请注意,在使用此方法之前,最好确保字符串仅由十进制数字组成

或者,使用
int?
作为聚合值来处理错误处理:

"12x34".Aggregate((int?)0, (s,c)=>  c>='0'&&c<='9' ? c-'0'+10*s : null)

虽然这可以用三元的
?:
操作符表达得稍微短一些,但这样做意味着依赖于表达式中的副作用,这对我的可读性并没有好处。

我在采访中被问了9000多次这个问题:)此版本能够处理负数,并能很好地处理其他情况:

public static int ToInt(string s)
{
    bool isNegative = false, gotAnyDigit = false;
    int result = 0;

    foreach (var ch in s ?? "")
    {
        if(ch == '-' && !(gotAnyDigit || isNegative))
        {
            isNegative = true;
        }
        else if(char.IsDigit(ch))
        {
            result = result*10 + (ch - '0');
            gotAnyDigit = true;
        }
        else
        {
            throw new ArgumentException("Not a number");
        }
    }

    if (!gotAnyDigit)
        throw new ArgumentException("Not a number");

    return isNegative ? -result : result;
}
还有几个懒惰的测试:

    [TestFixture]
public class Tests
{
    [Test]
    public void CommonCases()
    {
        foreach (var sample in new[]
            {
                new {e = 123, s = "123"},
                new {e = 110, s = "000110"},
                new {e = -011000, s = "-011000"},
                new {e = 0, s = "0"},
                new {e = 1, s = "1"},
                new {e = -2, s = "-2"},
                new {e = -12223, s = "-12223"},
                new {e = int.MaxValue, s = int.MaxValue.ToString()},
                new {e = int.MinValue, s = int.MinValue.ToString()}
            })
        {
            Assert.AreEqual(sample.e, Impl.ToInt(sample.s));
        }
    }
    [Test]
    public void BadCases()
    {
        var samples = new[] { "1231a", null, "", "a", "-a", "-", "12-23", "--1" };
        var errCount = 0;

        foreach (var sample in samples)
        {
            try
            {
                Impl.ToInt(sample);
            }
            catch(ArgumentException)
            {
                errCount++;
            }
        }

        Assert.AreEqual(samples.Length, errCount);
    }
}

+1.诀窍确实是向后迭代字符。+1,我想我更喜欢这里面的逻辑,因为它不使用额外的变量(my
factor
)然后以自然的顺序循环字符串。非常好的帖子,我希望我能投两次票。很高兴看到像你这样的人跳出框框思考;你提出了几个非常有效的观点。就我个人而言,我认为测试候选人的基本逻辑/数学思维技能不是一个坏主意。当然,他们可以用一个问题在框架中没有内置的方法,但这仍然是一个很好的问题。我知道我在几年前实现我的第一个
atoi
时,我必须思考几秒钟(顺便说一句,atoi
,是这个的C标准函数。我不明白你所说的“C编码技能”是什么意思)为什么不直接从if内部返回null?@Matti(继续)我同意基本的编码问题对于面试来说是公平的,但我更愿意看到面试官使用正确使用.NET的问题,而不是像这一个那样切中要害。我已经冒昧地修改了你的代码示例,以便它编译并做它应该做的事情-但我真的认为你应该请澄清或删除有关unicode和字符数组的误导性(或至少措辞拙劣)观点。感谢您的更正;我当时正在从头开始编写代码,但错过了“out”关键字,以及属性问题。我开始使用.net framwork和Int.Parse,但他们告诉我这基本上就是他们想要我生成的函数。这项工作是作为测试工程师在Microsoft完成的,我才知道我没有得到这项工作:)这项工作几乎符合以下条件:)需要一点时间才能习惯,但这就是S是lambda经常看起来的样子——如果你在VisualStudio中编写代码,它会自动插入人类友好的间距——我绝对崇拜的一个特性,希望它也可以是C++模式…实际上,我仍然在等待一个实用的IDE,它比语法高亮更进一步,包括内联字体和样式更改。更好地说明表达式的语义-例如,不强调没有语义意义的方括号和大括号,而是强调那些影响求值顺序的方括号和大括号;强制语义相关缩进,使复合标记如
=>
=
看起来
    [TestFixture]
public class Tests
{
    [Test]
    public void CommonCases()
    {
        foreach (var sample in new[]
            {
                new {e = 123, s = "123"},
                new {e = 110, s = "000110"},
                new {e = -011000, s = "-011000"},
                new {e = 0, s = "0"},
                new {e = 1, s = "1"},
                new {e = -2, s = "-2"},
                new {e = -12223, s = "-12223"},
                new {e = int.MaxValue, s = int.MaxValue.ToString()},
                new {e = int.MinValue, s = int.MinValue.ToString()}
            })
        {
            Assert.AreEqual(sample.e, Impl.ToInt(sample.s));
        }
    }
    [Test]
    public void BadCases()
    {
        var samples = new[] { "1231a", null, "", "a", "-a", "-", "12-23", "--1" };
        var errCount = 0;

        foreach (var sample in samples)
        {
            try
            {
                Impl.ToInt(sample);
            }
            catch(ArgumentException)
            {
                errCount++;
            }
        }

        Assert.AreEqual(samples.Length, errCount);
    }
}