如何截断.NET字符串?

Ste*_*idi 379 .net c# string truncate

我想截断一个字符串,使其长度不超过给定值.我正在写一个数据库表,并希望确保我写的值符合列的数据类型的约束.

例如,如果我可以编写以下内容会很好:

string NormalizeLength(string value, int maxLength)
{
    return value.Substring(0, maxLength);
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这会引发异常,因为maxLength通常会超出字符串的边界value.当然,我可以编写如下的函数,但我希望这样的东西已经存在.

string NormalizeLength(string value, int maxLength)
{
    return value.Length <= maxLength ? value : value.Substring(0, maxLength);
} 
Run Code Online (Sandbox Code Playgroud)

执行此任务的难以捉摸的API在哪里?有吗?

LBu*_*kin 579

Truncate()遗憾的是,字符串上没有方法.你必须自己写这种逻辑.但是,你可以做的是将它包装在扩展方法中,这样你就不必在任何地方复制它:

public static class StringExt
{
    public static string Truncate(this string value, int maxLength)
    {
        if (string.IsNullOrEmpty(value)) return value;
        return value.Length <= maxLength ? value : value.Substring(0, maxLength); 
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以写:

var someString = "...";
someString = someString.Truncate(2);
Run Code Online (Sandbox Code Playgroud)

  • @Bernard,如果maxLength为负,这应该会失败.任何其他行为都是意外的. (41认同)
  • 您可以在空值上调用扩展方法. (12认同)
  • 只要您在VS 2008中,大概是VS 2010,即使定位.Net 2.0,您仍然可以做到这一点.http://www.danielmoth.com/Blog/Using-Extension-Methods-In-Fx-20-Projects.aspx (7认同)
  • 伟大的解决方案,但记住这只适用于NET 3.5和Up.不要在NET2.0中尝试它. (5认同)
  • 当`maxLength`为负值时,这将失败. (4认同)
  • 添加一个可选的第三个参数`string ellipsis =""`可能很有用,你可以使用它像``myLongUsername".Truncate(9,"...")`这将返回`"myLong ..." `.在截断字符串的地方必须考虑省略号的长度,因此代码基本上会从`value.Substring(0,maxLength)`变为`value.Substring(0,maxLength - ellipsis.Length)+省略号`. (3认同)
  • 我不认为IsNullOrEmpty检查是否必要?(1)如果value为null,则无法在其上调用此扩展方法.(2)如果value是空字符串,则写入的return语句(在下一行)将返回空字符串. (2认同)
  • @mmcrae:string.Take返回IEnumerable &lt;char&gt;。以下是将其转换为字符串的一些方法:http://stackoverflow.com/questions/11654190/ienumerablechar-to-string (2认同)

Caf*_*eek 118

或者代替三元运算符,您可以使用Math.min

public static class StringExt
{
    public static string Truncate( this string value, int maxLength )
    {
        if (string.IsNullOrEmpty(value)) { return value; }

        return value.Substring(0, Math.Min(value.Length, maxLength));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 聪明!并且以下表达式被优化以返回对原始字符串的引用:`value.Substring(0,value.Length)`. (10认同)
  • @Bernard,框架中有很多东西......但是如果我检查它......我要么必须将`maxLength`默认为`0`或`value.Length`; 或者我需要抛出一个`ArgumentOutOfRangeException` ...在这种情况下更有意义,并且无论如何已经被`Substring`抛出了. (7认同)
  • 不幸的是,它没有针对value.Length小于MaxLength的情况进行优化,这可能是某些数据中的常见情况.字符串上的Length属性也应该大写. (4认同)
  • 短一点:`return string.IsNullOrEmpty(value) ? value : value.Substring(0, Math.Min(value.Length, maxLength));` (4认同)

jpi*_*son 39

我想我会抛弃我的实现,因为我相信它涵盖了其他人已经触及的所有案例,并且以简洁的方式这样做仍然是可读的.

public static string Truncate(this string value, int maxLength)
{
    if (!string.IsNullOrEmpty(value) && value.Length > maxLength)
    {
        return value.Substring(0, maxLength);
    }

    return value;
}
Run Code Online (Sandbox Code Playgroud)

这个解决方案主要建立在Ray的解决方案之上,并通过使用this关键字打开了用作扩展方法的方法,正如LBushkin在他的解决方案中所做的那样.

  • @Bernard - 我建议不要为maxLength参数传递负值,因为它是一个意外的值.Substring方法采用相同的方法,因此没有理由改进它抛出的异常. (14认同)
  • @JonSchneider,IsNullOrEmpty是必需的,因为这是一个扩展方法.如果您有一个已分配null的类型字符串变量,则编译器在调用此方法之前不会插入空检查.从技术上讲,这仍然是静态类的静态方法.所以:stringVar.Truncate(2)编译为:StringExt.Truncate(stringVar,2); (7认同)

Dyl*_*son 35

在.NET 4.0中,您可以使用以下Take方法:

string.Concat(myString.Take(maxLength));
Run Code Online (Sandbox Code Playgroud)

没有测试效率!


drz*_*aus 35

因为性能测试很有趣:(使用linqpad扩展方法)

var val = string.Concat(Enumerable.Range(0, 50).Select(i => i % 10));

foreach(var limit in new[] { 10, 25, 44, 64 })
    new Perf<string> {
        { "newstring" + limit, n => new string(val.Take(limit).ToArray()) },
        { "concat" + limit, n => string.Concat(val.Take(limit)) },
        { "truncate" + limit, n => val.Substring(0, Math.Min(val.Length, limit)) },
        { "smart-trunc" + limit, n => val.Length <= limit ? val : val.Substring(0, limit) },
        { "stringbuilder" + limit, n => new StringBuilder(val, 0, Math.Min(val.Length, limit), limit).ToString() },
    }.Vs();
Run Code Online (Sandbox Code Playgroud)

truncate方法"显着"更快.#microoptimization

  • truncate10 5788 ticks过去了(0.5788 ms)[10K reps,5.788E-05 ms per]
  • smart-trunc10 8206 ticks已过去(0.8206 ms)[在10K reps中,每个8.206E-05 ms]
  • stringbuilder10 10557 ticks elapsed(1.0557 ms)[10K reps,0.00010557 ms per]
  • concat10 45495 ticks已过去(4.5495 ms)[以10K reps计,每秒0.00045495 ms]
  • newstring10 72535 ticks已过去(7.2535 ms)[以10K代表为单位,每个0.00072535 ms]

晚了

  • truncate44 8835 ticks过去了(0.8835 ms)[10K reps,8.835E-05 ms per]
  • stringbuilder44 13106 ticks过去了(1.3106 ms)[10K reps,0.00013106 ms per]
  • smart-trunc44 14821 ticks已过去(1.4821 ms)[在10K reps中,每个0.00014821 ms]
  • newstring44 144324 ticks逝去(14.4324 ms)[在10K reps中,每个0.00144324 ms]
  • concat44 174610经过时间(17.461毫秒)[10K次,每次0.0017461毫秒]

太长

  • smart-trunc64 6944 ticks已过去(0.6944 ms)[在10K reps中,每个6.944E-05 ms]
  • truncate64 7686 ticks过去了(0.7686 ms)[10K reps,7.686E-05 ms per]
  • stringbuilder64 13314 ticks已过去(1.3314 ms)[以10K reps计,每个0.00013314 ms]
  • newstring64 177481 ticks逝去(17.7481 ms)[10K reps,0.00177481 ms per]
  • concat64 241601经过时间(24.1601 ms)[以10K代表计,每次0.00241601 ms]


tam*_*mes 27

您可以使用LINQ ...它消除了检查字符串长度的需要.不可否认,也许不是最有效的,但它很有趣.

string result = string.Join("", value.Take(maxLength)); // .NET 4 Join
Run Code Online (Sandbox Code Playgroud)

要么

string result = new string(value.Take(maxLength).ToArray());
Run Code Online (Sandbox Code Playgroud)

  • @mmcrae Linq可能会更直接,但速度也慢很多.我的基准测试表示Linq约为400ms,而针对100万次迭代的子串仅约为24ms. (9认同)
  • 为什么这不是公认的答案?最直接的方法是,编写自己需要维护/记录的扩展方法,或使用诸如.Take之类的内置方法 (2认同)
  • 永远不要使用此解决方案。正如上面两条评论中所述,即使现有字符串不大于最大长度,也总是存在内存分配。而且它的速度非常慢。 (2认同)

Dar*_*ren 13

似乎还没有人发布这个:

public static class StringExt
{
    public static string Truncate(this string s, int maxLength)
    {
        return s != null && s.Length > maxLength ? s.Substring(0, maxLength) : s;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用&&运算符使其略微优于接受的答案.


Sea*_*nMC 13

我在一条线上做了这样的事情

value = value.Length > 1000 ? value.Substring(0, 1000) : value;
Run Code Online (Sandbox Code Playgroud)

  • @markamery 这是一个更短的替代方案,在您需要使用它时编写和更新的代码更少。不喜欢吗?不要使用它 (6认同)
  • -1; 这根本不会添加任何未在已接受答案中的内容。 (2认同)
  • 快速、简单、快速。这就是我所需要的。谢谢! (2认同)

Joe*_*Joe 11

.NET Framework有一个API来截断这样的字符串:

Microsoft.VisualBasic.Strings.Left(string, int);
Run Code Online (Sandbox Code Playgroud)

但是在C#应用程序中,你可能更喜欢自己动手而不是依赖于Microsoft.VisualBasic.dll,它的主要存在是向后兼容性.

  • @CamiloTerevinto - 它是随.NET Framework一起提供的API,可以从任何托管语言调用. (9认同)

小智 8

另一个解决方案:

return input.Substring(0, Math.Min(input.Length, maxLength));
Run Code Online (Sandbox Code Playgroud)

  • 非常优雅的解决方案+1 (2认同)
  • 很好,但这不适用于空字符串。 (2认同)
  • 这看起来与其他答案太相似:/sf/answers/194370431/ (2认同)

Boh*_*dan 6

最近 C# 中最简单的方法是:

string Trunc(string s, int len) => s?.Length > len ? s.Substring(0, len) : s;
Run Code Online (Sandbox Code Playgroud)

它返回较长字符串的截断值和其他情况下的原始字符串 - 包括空输入 - 这是由 ? 处理的 一元运算符。


Edw*_*ran 5

采用 @CaffGeek 并简化它:

public static string Truncate(this string value, int maxLength)
    {
        return string.IsNullOrEmpty(value) ? value : value.Substring(0, Math.Min(value.Length, maxLength));
    }
Run Code Online (Sandbox Code Playgroud)


小智 5

为什么不:

string NormalizeLength(string value, int maxLength)
{
    //check String.IsNullOrEmpty(value) and act on it. 
    return value.PadRight(maxLength).Substring(0, maxLength);
}
Run Code Online (Sandbox Code Playgroud)

即在事件value.Length < maxLength垫空间到最后或截断多余的部分。


nol*_*ogo 5

我知道这是一个老问题,但这是一个不错的解决方案:

public static string Truncate(this string text, int maxLength, string suffix = "...")
{
    string str = text;
    if (maxLength > 0)
    {
        int length = maxLength - suffix.Length;
        if (length <= 0)
        {
            return str;
        }
        if ((text != null) && (text.Length > maxLength))
        {
            return (text.Substring(0, length).TrimEnd(new char[0]) + suffix);
        }
    }
    return str;
}

var myString = "hello world"
var myTruncatedString = myString.Truncate(4);
Run Code Online (Sandbox Code Playgroud)

返回:你好...


Jam*_*ees 5

与C#6的Null传播算子类似的变体

public static string Truncate(this string value, int maxLength)
{
    return value?.Length <= maxLength ? value : value?.Substring(0, maxLength);
}
Run Code Online (Sandbox Code Playgroud)

请注意,我们基本上检查value这里是否为空两次.


Tob*_*ele 5

对于C#字符串,2016年仍然没有Truncate方法。但是-使用C#6.0语法:

public static class StringExtension
{
  public static string Truncate(this string s, int max) 
  { 
    return s?.Length > max ? s.Substring(0, max) : s ?? throw new ArgumentNullException(s); 
  }
}
Run Code Online (Sandbox Code Playgroud)

它就像一个魅力:

"Truncate me".Truncate(8);
Result: "Truncate"
Run Code Online (Sandbox Code Playgroud)


Ogn*_*rov 5

我的两分钱示例长度为 30 :

  var truncatedInput = string.IsNullOrEmpty(input) ? 
      string.Empty : 
      input.Substring(0, Math.Min(input.Length, 30));
Run Code Online (Sandbox Code Playgroud)


Sun*_*est 5

在 C# 8 中,可以使用新的 Ranges 功能...

value = value[..Math.Min(30, value.Length)];
Run Code Online (Sandbox Code Playgroud)


chi*_*tom 5

这是C# 9 的一行代码:

public static string? Truncate(this string? value, int maxLength) => value is null or "" || value.Length <= maxLength ? value : value[..maxLength];
Run Code Online (Sandbox Code Playgroud)