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

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

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


当前回答

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

如果你还不知道有一个版本的系统。内存(为以下情况提供了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>,以避免使用Span<T>的ToString()成员分配新字符串。

The BCL itself internally uses Span's, ReadOnlySpan's, Memory's, and ReadOnlyMemory's where possible to avoid issues and to help optimize the code, especially when you compile arrays that are known at compile time and so using an property that returns that new'd up array as an ReadOnlySpan<byte> actually optimizes the code at runtime as then the JIT would not call memcpy on the data and instead uses it since it just returns a Span and as such is a window to the data that is already allocated ahead of time resulting in:

更少的分配。 更少的分配时间。 使代码总体上更快地使用。

其他回答

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

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

返回:你好……

我知道这里已经有大量的答案,但这是一个我已经去了,它处理空字符串和传递的长度为负的情况:

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

以@CaffGeek为例进行简化:

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

c# 6的Null传播运算符的类似变体

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

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

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

如果你还不知道有一个版本的系统。内存(为以下情况提供了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>,以避免使用Span<T>的ToString()成员分配新字符串。

The BCL itself internally uses Span's, ReadOnlySpan's, Memory's, and ReadOnlyMemory's where possible to avoid issues and to help optimize the code, especially when you compile arrays that are known at compile time and so using an property that returns that new'd up array as an ReadOnlySpan<byte> actually optimizes the code at runtime as then the JIT would not call memcpy on the data and instead uses it since it just returns a Span and as such is a window to the data that is already allocated ahead of time resulting in:

更少的分配。 更少的分配时间。 使代码总体上更快地使用。