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

例如,如果我能写以下内容,那就太好了:

string NormalizeLength(string value, int maxLength)
{
    return value.Substring(0, maxLength);
}

不幸的是,这会引发异常,因为maxLength通常超过字符串值的边界。当然,我可以写一个像下面这样的函数,但我希望这样的东西已经存在了。

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

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


当前回答

因为性能测试很有趣:(使用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();

截断法“明显”更快。# microoptimization

早期

truncate10 5788滴答流逝(0.5788 ms) [10K次,5.788E-05 ms /次] smart-trunc10 8206滴答流逝(0.8206 ms) [10K次,8.206E-05 ms /次] stringbuilder10 10557滴答流逝(1.0557 ms) [10K次,0.00010557 ms /次] concat10 45495滴答流逝(4.5495 ms) [10K次,0.00045495 ms /次] 时间流逝(7.2535 ms) [10K次,0.00072535 ms /次]

Late

truncate44 8835滴答流逝(0.8835 ms) [10K次,8.835E-05 ms /次] 13106滴答流逝(1.3106 ms) [10K次,0.00013106 ms /次] smart-trunc44 14821滴答流逝(1.4821毫秒)[10K次,0.00014821毫秒/次] 时间流逝(14.4324 ms) [10K次,0.00144324 ms /次] concat44 174610滴答流逝(17.461毫秒)[每10K次,0.0017461毫秒]

太长时间

smart-trunc64 6944滴答流逝(0.6944毫秒)[在10K次中,6.944E-05毫秒每] truncate64 7686滴答流逝(0.7686 ms) [10K次,7.686E-05 ms /次] stringbuilder64 13314滴答流逝(1.3314 ms) [10K次,0.00013314 ms /次] 时间流逝(17.7481 ms) [10K次,0.00177481 ms /次] concat64 241601滴答流逝(24.1601毫秒)[每10K次,0.00241601毫秒]

其他回答

截断字符串

public static string TruncateText(string strText, int intLength)
{
    if (!(string.IsNullOrEmpty(strText)))
    {                                
        // split the text.
        var words = strText.Split(' ');

        // calculate the number of words
        // based on the provided characters length 
        // use an average of 7.6 chars per word.
        int wordLength = Convert.ToInt32(Math.Ceiling(intLength / 7.6));

        // if the text is shorter than the length,
        // display the text without changing it.
        if (words.Length <= wordLength)
            return strText.Trim();                

        // put together a shorter text
        // based on the number of words
        return string.Join(" ", words.Take(wordLength)) + " ...".Trim();
    }
        else
        {
            return "";
        }            
    }

请注意,截断字符串不仅仅意味着仅以指定的长度切割字符串,而且必须注意不要分割单词。

Eg字符串:这是一个测试字符串。

我想把它剪到11点。如果我们使用上面给出的任何一种方法,结果将是

这是一个

这不是我们想要的

我使用的方法可能也不是那么完美,但它可以处理大多数情况

public string CutString(string source, int length)
{
        if (source== null || source.Length < length)
        {
            return source;
        }
        int nextSpace = source.LastIndexOf(" ", length);
        return string.Format("{0}...", input.Substring(0, (nextSpace > 0) ? nextSpace : length).Trim());
} 

2016年c#字符串仍然没有截断方法。 但是-使用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); 
  }
}

它就像一个魔法:

"Truncate me".Truncate(8);
Result: "Truncate"

似乎还没有人发布这个:

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

使用&&操作符会使其略好于已接受的答案。

我的观点是,例子长度为30:

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