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

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

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在哪里?有吗?


当前回答

你可以用LINQ…它消除了检查字符串长度的需要。不可否认,这可能不是最有效的,但很有趣。

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

or

string result = new string(value.Take(maxLength).ToArray());

其他回答

你可以用LINQ…它消除了检查字符串长度的需要。不可否认,这可能不是最有效的,但很有趣。

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

or

string result = new string(value.Take(maxLength).ToArray());

不幸的是,字符串上没有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);

可选的后缀和c#8可空引用类型。

public static class StringExt
{
    public static string? Truncate(this string? value, int maxLength, string truncationSuffix = "…")
    {
        return value?.Length > maxLength
            ? value.Substring(0, maxLength) + truncationSuffix
            : value;
    }
}

写:

"abc".Truncate(2);          // "ab…"
"abc".Truncate(3);          // "abc"
((string)null).Truncate(3); // null

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

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

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

以@CaffGeek为例进行简化:

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