如果您只想接受字符串的一部分,则主要使用子字符串方法。 这有一个缺点,你必须首先测试字符串的长度,以避免错误。 例如,您希望将数据保存到数据库中,并希望将值剪切为前20个字符。
如果你执行temp.substring(0,20)但temp只保存10个字符,则抛出异常。
我看到有两种解决方案:
使用扩展方法拍摄
string temp = "1234567890";
var data= new string( temp.Take(20).ToArray());
--> data now holds "1234657890"
当使用Take方法时,在速度或内存使用方面是否有任何缺点。 好处是您不必编写所有if语句。
答案 0 :(得分:23)
如果你发现自己这么做了,为什么不写一个扩展方法?
例如:
using System;
namespace Demo
{
public static class Program
{
public static void Main(string[] args)
{
Console.WriteLine("123456789".Left(5));
Console.WriteLine("123456789".Left(15));
}
}
public static class StringExt
{
public static string Left(this string @this, int count)
{
if (@this.Length <= count)
{
return @this;
}
else
{
return @this.Substring(0, count);
}
}
}
}
答案 1 :(得分:12)
正如Henk Holtermand所说,Take()
创建IEnumerator
,然后您需要ToArray()
来电。
因此,如果性能在您的应用程序中很重要,或者您将在流程中多次执行子字符串,则性能可能会出现问题。
我编写了一个示例程序,以准确地确定Take()
方法的结果有多慢:
测试了一千万次:
以下是代码:
internal const int RETRIES = 10000000;
static void Main(string[] args)
{
string testString = Guid.NewGuid().ToString();
long timeSubstring = MeasureSubstring(testString);
long timeTake = MeasureTake(testString);
Console.WriteLine("Time substring: {0} ms, Time take: {1} ms",
timeSubstring, timeTake);
}
private static long MeasureSubstring(string test)
{
long ini = Environment.TickCount;
for (int i = 0; i < RETRIES; i++)
{
if (test.Length > 4)
{
string tmp = test.Substring(4);
}
}
return Environment.TickCount - ini;
}
private static long MeasureTake(string test)
{
long ini = Environment.TickCount;
for (int i = 0; i < RETRIES; i++)
{
var data = new string(test.Take(4).ToArray());
}
return Environment.TickCount - ini;
}
答案 2 :(得分:6)
首先我不想回答(因为已有有效的答案),但我想补充一些不适合作为评论的内容:
你在谈论性能/内存问题。对。正如其他人所说,string.SubString
更有效率,因为它是如何内部优化的,以及LINQ如何与string.Take()
一起使用(字符枚举......等)。
没有人说的是Take()
在你的情况下的主要缺点是它完全破坏了子串的简单性。正如蒂姆所说,要获得你想要的实际字符串,你必须写:
string myString = new string(temp.Take(20).ToArray());
该死的......这比理解起来要难得多(参见Matthew的扩展方法):
string myString = temp.Left(20);
LINQ非常适合大量用例,但如果没有必要,则不应使用。即使一个简单的循环有时比LINQ更好(即更快,更易读/可理解),所以想象一个简单的子串......
在您的案例中总结一下LINQ:
答案 3 :(得分:3)
@Daniel答案的变体对我来说似乎更准确
一个Guid的长度是36.我们正在创建一个列表,其中可变长度的字符串从1到36,我们的目标是使用html, body {
width: 100%;
height: 100%;
background: white;
margin:0;
padding:0;
}
/ substring
方法取18,所以大约一半将会经历。
我得到的结果表明,take
比Take
慢<6-10倍。
结果示例:
Substring
所以,对于 500万字符串,大致 250万次操作,总时间 2.1秒,或者 0.0008564毫秒每次操作= ~1微秒。如果你认为你需要将它减去5个子串,那就去吧,但我怀疑在现实生活中,在紧身衣圈之外,你会感受到不同。
Build time: 3812 ms
Time substring: 391 ms, Time take: 1828 ms
Build time: 4172 ms
Time substring: 406 ms, Time take: 2141 ms
答案 4 :(得分:2)
当使用Take方法时,在速度或内存使用方面是否有任何缺点
是。 Take()
首先需要创建一个IEnumerator<char>
,并且对于每个char,都要经过MoveNext()
和yield return;
等的箍。还要注意ToArray和字符串构造函数。
对于少量字符串不是问题,但在大循环中,专门的字符串函数要好得多。
答案 5 :(得分:1)
Take
扩展方法不创建子字符串,它返回一个查询,可用于创建Char[]
(ToArray)或List<Char>
(ToList)。但你实际上想拥有那个子串。
然后你还需要其他方法:
string data = new string(temp.Take(20).ToArray());
这隐含地使用foreach
来枚举字符,创建一个新的char [](由于加倍算法可能会分配太多的大小)。最后,从char[]
创建一个新字符串。
另一方面Substring
使用optimized methods。
所以你用记忆支付这个小便利,这可能是微不足道的,但并非总是如此。