如何在不使用 ToString() 的情况下将 Int 转换为 C# 中的字符串?
Posted
技术标签:
【中文标题】如何在不使用 ToString() 的情况下将 Int 转换为 C# 中的字符串?【英文标题】:How do I convert an Int to a String in C# without using ToString()? 【发布时间】:2013-07-08 15:53:40 【问题描述】:在不使用任何原生 toString 功能的情况下将以下 int 参数转换为字符串。
public string integerToString(int integerPassedIn) //Your code here
既然所有东西都继承自 Object
和 Object
有一个 ToString()
方法,你如何在不使用本机 ToString()
方法的情况下将 int
转换为 string
?
字符串连接的问题是它会调用ToString()
直到它碰到一个或碰到Object
类。
如何在 C# 中不使用ToString()
将整数转换为字符串?
【问题讨论】:
迭代 int mod 10,并将它们连接成新的字符串似乎是他们正在寻找的,但你说连接调用 toString?String str = "" + a;
会调用 toString 我认为这就是 @AMR 的意思
有人必须实现 ToString 而不调用 ToString。你认为他们是怎么做到的?
黑魔法......或者@EricLippert做到了......
@AMR 你为什么要问这个问题?这是一个面试/家庭作业问题,还是你只是好奇?
【参考方案1】:
类似这样的:
public string IntToString(int a)
var chars = new[] "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ;
var str = string.Empty;
if (a == 0)
str = chars[0];
else if (a == int.MinValue)
str = "-2147483648";
else
bool isNegative = (a < 0);
if (isNegative)
a = -a;
while (a > 0)
str = chars[a % 10] + str;
a /= 10;
if (isNegative)
str = "-" + str;
return str;
更新:这是另一个更短且性能更好的版本,因为它消除了所有字符串连接,有利于操作固定长度的数组。它最多支持 16 个碱基,但很容易将其扩展到更高的碱基。它可能会进一步改进:
public string IntToString(int a, int radix)
var chars = "0123456789ABCDEF".ToCharArray();
var str = new char[32]; // maximum number of chars in any base
var i = str.Length;
bool isNegative = (a < 0);
if (a <= 0) // handles 0 and int.MinValue special cases
str[--i] = chars[-(a % radix)];
a = -(a / radix);
while (a != 0)
str[--i] = chars[a % radix];
a /= radix;
if (isNegative)
str[--i] = '-';
return new string(str, i, str.Length - i);
【讨论】:
我正要写一些真正肮脏的东西,但这好多了 不错的答案。虽然是小错误:它在int.MinValue
上崩溃
@Daniel 它在检查的上下文中崩溃。在未经检查的上下文中,它只打印-
。
字符连接不会在幕后调用ToString()
方法吗?
是的,这个答案仍然不起作用。在这里查看答案一以了解为什么***.com/questions/3759343/automatic-tostring【参考方案2】:
这是我一直使用的解决方案:
public static string numberBaseChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static string IntToStringWithBase(int n, int b)
return IntToStringWithBase(n, b, 1);
public static string IntToStringWithBase(int n, int b, int minDigits)
if (minDigits < 1) minDigits = 1;
if (n == 0) return new string('0', minDigits);
string s = "";
if ((b < 2) || (b > numberBaseChars.Length)) return s;
bool neg = false;
if ((b == 10) && (n < 0)) neg = true; n = -n;
uint N = (uint)n;
uint B = (uint)b;
while ((N > 0) | (minDigits-- > 0))
s = numberBaseChars[(int)(N % B)] + s;
N /= B;
if (neg) s = "-" + s;
return s;
这看起来很复杂,但有以下特点:
支持基数 2 到 36 处理负值 可选的总位数【讨论】:
等一下,你真的有这个用途吗? @JohnBuchanan:当然!一个例子:我们有具有唯一值的 ID 芯片。我们使用基数 36 将值作为字符串处理,基数始终为 8 个字符:0016I2WM
。据我所知,这是任何.ToString()
都不可能的。有更好的方法吗?【参考方案3】:
我并不真正相信串联 operator +
调用 ToString
,但如果确实如此,您可以通过执行以下操作来避免这两个:
if (a == 0) return "0";
/* Negative maxint doesn't have a corresponding positive value, so handle it
* as a special case. Thanks to @Daniel for pointing this out.
*/
if (a == 0x80000000) return "-2147483648";
List<char> l = new List<char>();
bool negative = false;
if (a < 0)
negative = true;
a *= -1;
while (a > 0)
l.Add('0' + (char)(a % 10));
a /= 10;
if (negative) l.Add('-');
l.Reverse();
return new String(l.ToArray());
【讨论】:
+
运算符调用 ToString
以获取操作数类型为 object
的重载之一。当两个操作数都是字符串类型时,它不是。
@Servy 好的,我就是这么想的。感谢您的澄清。【参考方案4】:
整数从最低位到最高位进行处理。使用模 10 (%10) 计算单个数字,然后将其添加到字符值“0”。这会产生字符“0”、“1”、...、“9”之一。
这些数字被压入堆栈,因为它们在处理时必须以相反的顺序显示(最高有效位到最低有效位)。这样做而不是重复地将数字添加到字符串可能会更有效,但由于数字数量非常少,您必须执行基准测试才能确定。
处理非正数需要一些额外的处理。
public string IntToString(int a)
if (a == 0)
return "0";
if (a == int.MinValue)
return "-2147483648";
var isNegative = false;
if (a < 0)
a = -a;
isNegative = true;
var stack = new Stack<char>();
while (a != 0)
var c = a%10 + '0';
stack.Push((char) c);
a /= 10;
if (isNegative)
stack.Push('-');
return new string(stack.ToArray());
我的第一个版本使用StringBuilder
从字符数组中创建字符串,但要“从”StringBuilder
中获取字符串需要调用名为ToString
的方法。显然,这种方法不会做任何 int 到字符串的转换,这对我来说就是这个问题的意义所在。
但为了证明您可以在不调用 ToString
的情况下创建字符串,我已切换到使用 string
构造函数,我还认为它比使用 StringBuilder
更有效。
如果ToString
以任何形式被禁止,则您不能使用string.Concat
文档中所见的字符串连接:
该方法通过调用arg0和arg1的无参数ToString方法连接arg0和arg1;它不添加任何分隔符。
所以执行s += '1'
将调用'1'.ToString()
。但对我来说这并不重要。重要的部分是如何将 int 转换为字符串。
【讨论】:
在 StringBuilder 上使用 ToString 是否违反规则?另一种方法是使用 string += string。 我想是这样,因为 StringBuilder 是框架的一部分。虽然我不是 OP :) 我现在已经不再使用ToString
来满足评论者的需求,甚至提供了一个不使用 ToString
的答案,因为字符串连接在幕后。【参考方案5】:
争取更短的版本,以及使用Math.DivRem
的版本:
string IntToString(int a)
if (a == int.MinValue)
return "-2147483648";
if (a < 0)
return "-" + IntToString(-a);
if (a == 0)
return "0";
var s = "";
do
int r;
a = Math.DivRem(a, 10, out r);
s = new string((char)(r + (int)'0'), 1) + s;
while (a > 0);
return s;
使用new string(..., 1)
构造函数只是满足OP 要求ToString
不被任何东西调用的一种方式。
【讨论】:
【参考方案6】:您可以像这样将任何数字转换为字符
byte = (char)(byte)(digit+48)
幻数48
是字符0
的ASCII 值,它们在ASCII 表中是连续的,因此您只需添加数字即可在ASCII 表中得到相应的值。
并且您可以使用模运算符%
迭代地获取整数中的数字
从 pswg 借用一般结构,你会得到
public string IntToString(int a)
var str = string.Empty;
bool isNegative = false;
if (a < 0)
isNegative = true;
a = -a;
do
str = (char)(byte)((a % 10) + 48) + str;
a /= 10;
while(a > 0);
return isNegative ? '-' + str : str
【讨论】:
【参考方案7】:这是我使用迭代和递归以及运行时分析的看法。
public static class IntegerToString
static char[] d = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
public static string Iteration(int num, int radix = 10)
if (num == 0) return "0";
if (num < 0) return "-" + Iteration(Math.Abs(num));
var r = new List<char>();
while (num > 0)
r.Insert(0, d[num % radix]);
num /= radix;
return new string(r.ToArray());
public static string Recursion(int num, int radix = 10)
if (num == 0) return "0";
if (num < 0) return "-" + Recursion(Math.Abs(num));
return (num > radix - 1 ? Recursion(num / radix) : "") + d[num % radix];
要点
处理基数 2 到 36(警告:您必须确保基数正确,因为没有异常处理。 递归方法只有3行! (代码高尔夫风格)分析
以下是两种方法在我的电脑上与标准ToString()
相比的运行时分析。
50 runs of 100000 items per set
Running Time:
Iteration: 00:00:02.3459591 (00:00:00.0469191 avg)
Recursion: 00:00:02.1359731 (00:00:00.0427194 avg)
Standard : 00:00:00.4271253 (00:00:00.0085425 avg)
Ratios:
| Iter | Rec | Std
-----+------+------+-----
Iter | 1.00 | 0.91 | 0.18
Rec | 1.10 | 1.00 | 0.20
Std | 5.49 | 5.00 | 1.00
结果表明迭代和递归方法的运行速度比标准的ToString()
方法慢 5.49 和 5.00 倍。
这是我用于分析的代码:
class Program
static void Main(string[] args)
var r = new Random();
var sw = new System.Diagnostics.Stopwatch();
var loop = new List<long>();
var recr = new List<long>();
var std = new List<long>();
var setSize = 100000;
var runs = 50;
Console.WriteLine("0 runs of 1 items per set", runs, setSize);
for (int j = 0; j < runs; j++)
// create number set
var numbers = Enumerable.Range(1, setSize)
.Select(s => r.Next(int.MinValue,
int.MaxValue))
.ToArray();
// loop
sw.Start();
for (int i = 0; i < setSize; i++)
IntegerToString.Iteration(numbers[i]);
sw.Stop();
loop.Add(sw.ElapsedTicks);
// recursion
sw.Reset();
sw.Start();
for (int i = 0; i < setSize; i++)
IntegerToString.Recursion(numbers[i]);
sw.Stop();
recr.Add(sw.ElapsedTicks);
// standard
sw.Reset();
sw.Start();
for (int i = 0; i < setSize; i++)
numbers[i].ToString();
sw.Stop();
std.Add(sw.ElapsedTicks);
Console.WriteLine();
Console.WriteLine("Running Time:");
Console.WriteLine("Iteration: 0 (1 avg)",
TimeSpan.FromTicks(loop.Sum()),
TimeSpan.FromTicks((int)loop.Average()));
Console.WriteLine("Recursion: 0 (1 avg)",
TimeSpan.FromTicks(recr.Sum()),
TimeSpan.FromTicks((int)recr.Average()));
Console.WriteLine("Standard : 0 (1 avg)",
TimeSpan.FromTicks(std.Sum()),
TimeSpan.FromTicks((int)std.Average()));
double lSum = loop.Sum();
double rSum = recr.Sum();
double sSum = std.Sum();
Console.WriteLine();
Console.WriteLine("Ratios: \n" +
" | Iter | Rec | Std \n" +
"-----+------+------+-----");
foreach (var div in new[] new n = "Iter", t = lSum,
new n = "Rec ", t = rSum,
new n = "Std ", t = sSum)
Console.WriteLine("0 | 1:0.00 | 2:0.00 | 3:0.00",
div.n, lSum / div.t, rSum / div.t, sSum / div.t);
Console.ReadLine();
【讨论】:
【参考方案8】: public static string integerToString(int integerPassedIn)
if (integerPassedIn == 0) return "0";
var negative = integerPassedIn < 0;
var res = new List<char>();
while(integerPassedIn != 0)
res.Add((char)(48 + Math.Abs(integerPassedIn % 10)));
integerPassedIn /= 10;
res.Reverse();
if (negative) res.Insert(0, '-');
return new string(res.ToArray());
【讨论】:
【参考方案9】:递归:
public static string integerToString(int integerPassedIn)
ICollection<char> res = new List<char>();
IntToStringRecusion(integerPassedIn, res);
if (integerPassedIn < 0) res.Add('-');
return new string(res.Reverse().ToArray()).PadLeft(1,'0');
static void IntToStringRecusion(int integerPassedIn, ICollection<char> array)
if (integerPassedIn == 0) return;
array.Add((char)(48 + Math.Abs(integerPassedIn % 10)));
IntToStringRecusion(integerPassedIn / 10, array);
【讨论】:
【参考方案10】:简单易懂:
string s = 5 + ""
//s = "5"
【讨论】:
使用上述方法时,会调用ToString @我没有看到这里调用的“ToString()” C# 像这样连接时会调用 tostring以上是关于如何在不使用 ToString() 的情况下将 Int 转换为 C# 中的字符串?的主要内容,如果未能解决你的问题,请参考以下文章