470

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

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

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

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

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

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

4

37 回答 37

741

不幸的是,没有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); 
    }
}

现在我们可以写:

var someString = "...";
someString = someString.Truncate(2);
2021-09-17 后缀和 c#8 可空引用类型的替代方案。
public static class StringExt
{
    public static string? Truncate(this string? value, int maxLength, string truncationSuffix = "…&quot;)
    {
        return value?.Length > maxLength
            ? value.Substring(0, maxLength) + truncationSuffix
            : value;
    }
}

来写:

"abc".Truncate(2);          // "ab…&quot;
"abc".Truncate(3);          // "abc"
((string)null).Truncate(3); // null
于 2010-05-05T20:52:53.393 回答
158

或者代替三元运算符,您可以使用 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));
    }
}
于 2010-05-05T20:57:36.347 回答
48

我想我会投入我的实现,因为我相信它涵盖了其他人已经触及的所有案例,并且以一种仍然可读的简洁方式进行。

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

    return value;
}

该解决方案主要建立在Ray 的解决方案之上,并像LBushkin在他的解决方案中所做的那样,通过使用this关键字打开该方法以用作扩展方法。

于 2011-05-03T14:20:13.910 回答
46

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

truncate方法“明显”更快。#微优化

早期的

  • truncate10 经过 5788 个刻度(0.5788 毫秒)[以 10K 次重复,每次 5.788E-05 毫秒]
  • smart-trunc10 8206 个滴答经过 (0.8206 ms) [以 10K 次重复,每次 8.206E-05 ms]
  • stringbuilder10 经过 10557 个滴答声(1.0557 毫秒)[以 10K 次重复,每次 0.00010557 毫秒]
  • concat10 45495 个滴答经过(4.5495 毫秒)[以 10K 次重复,每 0.00045495 毫秒]
  • newstring10 72535 个滴答经过(7.2535 毫秒)[以 10K 次重复,每 0.00072535 毫秒]

晚的

  • truncate44 经过 8835 个刻度(0.8835 毫秒)[以 10K 次重复,每次 8.835E-05 毫秒]
  • stringbuilder44 13106 个滴答经过(1.3106 毫秒)[以 10K 次重复,每 0.00013106 毫秒]
  • smart-trunc44 14821 个滴答经过 (1.4821 ms) [in 10K reps, 0.00014821 ms per]
  • newstring44 144324 个滴答经过(14.4324 毫秒)[以 10K 次重复,每 0.00144324 毫秒]
  • concat44 174610 个滴答经过(17.461 毫秒)[以 10K 次重复,每 0.0017461 毫秒]

太长

  • smart-trunc64 6944 个滴答经过 (0.6944 ms) [in 10K reps, 6.944E-05 ms per]
  • truncate64 7686 滴答经过(0.7686 毫秒)[以 10K 次重复,每次 7.686E-05 毫秒]
  • stringbuilder64 13314 个滴答经过(1.3314 毫秒)[以 10K 次重复,每 0.00013314 毫秒]
  • newstring64 177481 个滴答经过(17.7481 毫秒)[以 10K 次重复,每 0.00177481 毫秒]
  • concat64 241601 滴答经过(24.1601 毫秒)[以 10K 次重复,每 0.00241601 毫秒]
于 2016-12-01T19:00:40.517 回答
42

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

string.Concat(myString.Take(maxLength));

没有测试效率!

于 2013-12-06T04:08:27.637 回答
30

您可以使用 LINQ... 它消除了检查字符串长度的需要。诚然,这可能不是最有效的,但它很有趣。

string result = string.Join("", value.Take(maxLength)); // .NET 4 Join

或者

string result = new string(value.Take(maxLength).ToArray());
于 2010-05-05T20:59:56.273 回答
29

另一种解决方案:

return input.Substring(0, Math.Min(input.Length, maxLength));
于 2019-02-02T09:09:15.913 回答
22

我像这样在一行中做了我的

value = value.Length > 1000 ? value.Substring(0, 1000) : value;
于 2017-05-23T16:30:48.133 回答
17

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

Microsoft.VisualBasic.Strings.Left(string, int);

但在 C# 应用程序中,您可能更愿意自己开发,而不是依赖 Microsoft.VisualBasic.dll,后者的主要存在理由是向后兼容。

于 2012-11-08T14:46:43.987 回答
16

好像还没有人发过这个:

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

使用 && 运算符使其比接受的答案略好。

于 2014-10-03T08:38:23.597 回答
7

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

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);

回复:你好...

于 2014-02-27T22:16:37.677 回答
7

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

value = value[..Math.Min(30, value.Length)];
于 2020-01-08T05:21:26.390 回答
6

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"
于 2016-10-28T14:30:48.783 回答
5

为什么不:

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

即在事件中将value.Length < maxLength空格填充到末尾或截断多余的部分。

于 2013-08-29T15:47:43.140 回答
5

具有 C# 6 的 Null 传播运算符的类似变体

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

请注意,我们实际上value是在这里检查两次是否为空。

于 2016-04-19T14:19:59.790 回答
4

采用@CaffGeek 并对其进行简化:

public static string Truncate(this string value, int maxLength)
    {
        return string.IsNullOrEmpty(value) ? value : value.Substring(0, Math.Min(value.Length, maxLength));
    }
于 2013-03-26T18:56:39.837 回答
4

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

例如字符串:这是一个测试字符串。

我想在 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());
} 
于 2013-05-29T04:55:38.987 回答
4

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

string Trunc(string s, int len) => s?.Length > len ? s.Substring(0, len) : s;

它为较长的字符串返回截断的值,对于其他情况(包括空输入)返回原始字符串,由 ? 一元运算符。

于 2020-12-08T16:27:37.993 回答
3

以防万一这里没有足够的答案,这是我的:)

public static string Truncate(this string str, 
                              int totalLength, 
                              string truncationIndicator = "")
{
    if (string.IsNullOrEmpty(str) || str.Length < totalLength) 
        return str;

    return str.Substring(0, totalLength - truncationIndicator.Length) 
           + truncationIndicator;
}

使用:

"I use it like this".Truncate(5,"~")
于 2014-11-26T18:09:56.547 回答
3

我的两美分,示例长度为 30 :

  var truncatedInput = string.IsNullOrEmpty(input) ? 
      string.Empty : 
      input.Substring(0, Math.Min(input.Length, 30));
于 2019-07-04T07:42:19.050 回答
3

我知道这里已经有很多答案,但这是我使用的答案,它处理空字符串和传入长度为负的情况:

public static string Truncate(this string s, int length)
{
    return string.IsNullOrEmpty(s) || s.Length <= length ? s 
        : length <= 0 ? string.Empty 
        : s.Substring(0, length);
}
于 2018-03-14T11:11:33.647 回答
2

为了(过度)复杂性,我将添加我的重载版本,它将最后 3 个字符替换为关于 maxLength 参数的省略号。

public static string Truncate(this string value, int maxLength, bool replaceTruncatedCharWithEllipsis = false)
{
    if (replaceTruncatedCharWithEllipsis && maxLength <= 3)
        throw new ArgumentOutOfRangeException("maxLength",
            "maxLength should be greater than three when replacing with an ellipsis.");

    if (String.IsNullOrWhiteSpace(value)) 
        return String.Empty;

    if (replaceTruncatedCharWithEllipsis &&
        value.Length > maxLength)
    {
        return value.Substring(0, maxLength - 3) + "...";
    }

    return value.Substring(0, Math.Min(value.Length, maxLength)); 
}
于 2014-01-09T16:26:26.127 回答
1

我知道.net 中没有任何内容 - 这是我的版本,它添加了“...”:

public static string truncateString(string originalString, int length) {
  if (string.IsNullOrEmpty(originalString)) {
   return originalString;
  }
  if (originalString.Length > length) {
   return originalString.Substring(0, length) + "...";
  }
  else {
   return originalString;
  }
}
于 2010-05-05T20:57:13.923 回答
1

我更喜欢 jpierson 的回答,但我在这里看到的所有示例都没有处理无效的 maxLength 参数,例如当 maxLength < 0 时。

选择可以是在 try/catch 中处理错误,将 maxLength 参数 min 限制为 0,或者如果 maxLength 小于 0,则返回一个空字符串。

未优化代码:

public string Truncate(this string value, int maximumLength)
{
    if (string.IsNullOrEmpty(value) == true) { return value; }
    if (maximumLen < 0) { return String.Empty; }
    if (value.Length > maximumLength) { return value.Substring(0, maximumLength); }
    return value;
}
于 2013-03-23T19:36:34.220 回答
1

这是一个 vb.net 解决方案,标记 if(虽然丑陋)语句提高了性能,因为当 string 已经小于 maxlength 时我们不需要 substring 语句......通过使其成为 string 的扩展,它很容易使用。 ..

 <System.Runtime.CompilerServices.Extension()> _
    Public Function Truncate(String__1 As String, maxlength As Integer) As String
        If Not String.IsNullOrEmpty(String__1) AndAlso String__1.Length > maxlength Then
            Return String__1.Substring(0, maxlength)
        Else
            Return String__1
        End If
    End Function
于 2015-01-20T08:33:43.557 回答
1

流行的库Humanizer有一个Truncate方法。使用 NuGet 安装:

Install-Package Humanizer
于 2020-08-19T20:01:26.027 回答
1

我知道已经有很多答案,但我需要保持字符串的开头和结尾完整,但将其缩短到最大长度以下。

    public static string TruncateMiddle(string source)
    {
        if (String.IsNullOrWhiteSpace(source) || source.Length < 260) 
            return source;

        return string.Format("{0}...{1}", 
            source.Substring(0, 235),
            source.Substring(source.Length - 20));
    }

这用于创建最大长度为 260 个字符的 SharePoint URL。

我没有将长度作为参数,因为它是一个常数 260。我也没有将第一个子字符串长度作为参数,因为我希望它在特定点中断。最后,第二个子字符串是源的长度 - 20,因为我知道文件夹结构。

这可以很容易地适应您的特定需求。

于 2016-11-16T16:37:34.960 回答
1

这是一个C# 9单行代码:

public static string Truncate(this string value, int maxLength) => value is null or "" || value.Length <= maxLength ? value : value[..maxLength];
于 2021-03-10T15:48:33.670 回答
0

作为上述可能性的补充,我想分享我的解决方案。它是一种扩展方法,允许 null(返回 string.Empty),还有第二个 .Truncate() 用于将其与省略号一起使用。请注意,它不是性能优化的。

public static string Truncate(this string value, int maxLength) =>
    (value ?? string.Empty).Substring(0, (value?.Length ?? 0) <= (maxLength < 0 ? 0 : maxLength) ? (value?.Length ?? 0) : (maxLength < 0 ? 0 : maxLength));
public static string Truncate(this string value, int maxLength, string ellipsis) =>
    string.Concat(value.Truncate(maxLength - (((value?.Length ?? 0) > maxLength ? ellipsis : null)?.Length ?? 0)), ((value?.Length ?? 0) > maxLength ? ellipsis : null)).Truncate(maxLength);
于 2018-11-15T12:45:47.187 回答
0

基于thisthis,这里有两个版本也适用于“高达”值的负值。这第一个不允许通过上限为 0 默默地允许负值:

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

这是一个循环:

private static int Mod(this int a, int n) => (((a %= n) < 0) ? n : 0) + a;

public static string Truncate(this string value, int maxLength)
{
    return string.IsNullOrEmpty(value) ?
        value :
        value.Substring(0, maxLength.Mod(value.Length));
}
于 2020-12-23T22:48:55.390 回答
0

您可以创建一个Truncate扩展方法,将最大长度与字符串长度进行比较,并Substring在需要时调用。

如果您想要与 的类似的空处理行为Substring,请不要包含空检查。这样,就像str.Substring(0, 10)throws a NullReferenceExceptionifstr为 null 一样,str.Truncate(10).

public static class StringExtensions
{
    public static string Truncate(this string value, int maxLength) =>
        value.Length <= maxLength ? value : value.Substring(0, maxLength); 
}
于 2020-08-19T19:56:25.667 回答
0

所有其他答案都没有考虑到 Span,它比 .NET 中字符串类型的 Substring 性能更高

如果您还不知道有一个 System.Memory 版本(它提供 Span、ReadOnlySpan、Memory 和 ReadOnlyMemory,用于以下情况:

如此简单的实现可能如下:

public static string Truncate(this string value, int maxLength)
{
    if (!string.IsNullOrEmpty(value) && value.Length > maxLength)
    {
        return value.AsSpan(0, maxLength).ToString(); /* Note the use of AsSpan instead of Substring. */
    }

    return value;
}

理论上可以使该方法返回Span<char>,以避免使用 的ToString()成员分配新字符串Span<T>

BCL 本身在内部尽可能使用 Span、ReadOnlySpan、Memory 和 ReadOnlyMemory 来避免问题并帮助优化代码,尤其是当您编译在编译时已知的数组时,因此使用返回该新数组的属性作为anReadOnlySpan<byte>实际上会在运行时优化代码,因为 JIT 不会调用memcpy数据而是使用它,因为它只返回一个 Span 并且因此是一个已经提前分配的数据的窗口,导致:

  1. 更少的分配。
  2. 分配时间更少。
  3. 使代码整体使用起来更快。
于 2021-04-27T09:37:52.483 回答
0

截断字符串

public static string _TruncateString(string input, int charaterlimit)
{
    int characterLimit = charaterlimit;
    string output = input;

    // Check if the string is longer than the allowed amount
    // otherwise do nothing
    if (output.Length > characterLimit && characterLimit > 0)
    {
        // cut the string down to the maximum number of characters
        output = output.Substring(0, characterLimit);
        // Check if the character right after the truncate point was a space
        // if not, we are in the middle of a word and need to remove the rest of it
        if (input.Substring(output.Length, 1) != " ")
        {
            int LastSpace = output.LastIndexOf(" ");

            // if we found a space then, cut back to that space
            if (LastSpace != -1)
            {
                output = output.Substring(0, LastSpace);
            }
        }
        // Finally, add the "..."
        output += "...";
    }
    return output;
}
于 2016-01-25T09:17:24.850 回答
-1
public static string Truncate( this string value, int maxLength )
    {
        if (string.IsNullOrEmpty(value)) { return value; }

        return new string(value.Take(maxLength).ToArray());// use LINQ and be happy
    }
于 2013-05-17T20:19:21.900 回答
-3

截断字符串

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 "";
        }            
    }
于 2016-05-27T13:39:11.113 回答
-4

这是我通常使用的代码:

string getSubString(string value, int index, int length)
        {
            if (string.IsNullOrEmpty(value) || value.Length <= length)
            {
                return value;
            }
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            for (int i = index; i < length; i++)
            {
                sb.AppendLine(value[i].ToString());
            }
            return sb.ToString();
        }
于 2014-09-19T23:52:34.953 回答
-4

我建议使用 substring 方法来实现相同的有效功能。

    // Gets first n characters.
    string subString = inputString.Substring(0, n);

这样做的好处是可以让您从任一侧甚至中间某处拼接字符串,而无需编写额外的方法。希望有帮助:)

如需其他参考:https ://www.dotnetperls.com/substring

于 2018-02-16T19:20:03.097 回答