在C#中,我希望修剪()字符串两端的所有可能类型的空格字符(由.IsWhitesspace定义),并修剪字符串的开头,以便还从char[]数组中的自定义列表中删除出现在常规字母数字字符之前的任何字符.因此,字符串的结尾应该是第一个字符不是任何空格,也不是我的定制列表中的字符之一.(当然,字符串可以在第一个字符之后包括空格或我的列表中的字符.)

我只想遍历字符串一次来完成所有这些操作,因为有一个很大的字符串列表需要修剪.

以下代码不起作用(请参阅代码片段下面的更多注释).

    static class TrimmerExtension
    {
        private const string _prefixCharsToTrimAsString = "~`$|-_";
        private static readonly char[] _prefixCharsToTrim;

        // static ctor
        static TrimmerExtension()
        {
            _prefixCharsToTrim = _prefixCharsToTrimAsString.ToCharArray();
        }

        public static string TrimWhitespaceAndPrefixes(this string s)
        {
            return s.Trim().TrimStart(_prefixCharsToTrim).TrimStart();
        }
    }

上述方法不起作用,因为:

  1. 它多次调用不同版本的Trim,从而多次迭代字符串.(因此,上述方法效率低下);

  2. 如果要修剪的其他字符之间有空格字符,则它不会从开头完全修剪所有空格和特殊字符;例如,如果字符串包含"$~Something",则扩展方法将返回"~Something",但前两个字符仍然需要删除.(所以上面的代码是不正确的.)

C#或.NET是否提供了一种有效的方法来实现这一点(在性能和源代码简单性方面)?或者,是否有类或库定义了所有可能的空格字符的常量字符(或字符串)数组,Trim()函数将从字符串中删除这些字符,以便我可以将其添加到要删除的特殊前缀字符列表中?

如果此特定问题已得到回答,请发布问题和答案的链接.

谢谢.

推荐答案

看起来没有简单的方法,因为string.Trim()内部使用两种不同的方法.

用于空格的TrimWhiteSpaceHelper:

    private string TrimWhiteSpaceHelper(TrimType trimType)
    {
        // end will point to the first non-trimmed character on the right.
        // start will point to the first non-trimmed character on the left.
        int end = Length - 1;
        int start = 0;

        // Trim specified characters.
        if ((trimType & TrimType.Head) != 0)
        {
            for (start = 0; start < Length; start++)
            {
                if (!char.IsWhiteSpace(this[start]))
                {
                    break;
                }
            }
        }

        if ((trimType & TrimType.Tail) != 0)
        {
            for (end = Length - 1; end >= start; end--)
            {
                if (!char.IsWhiteSpace(this[end]))
                {
                    break;
                }
            }
        }

        return CreateTrimmedString(start, end);
    }

和用于自定义字符的TrimHelper:

private unsafe string TrimHelper(char* trimChars, int trimCharsLength, TrimType trimType)
    {
        Debug.Assert(trimChars != null);
        Debug.Assert(trimCharsLength > 0);

        // end will point to the first non-trimmed character on the right.
        // start will point to the first non-trimmed character on the left.
        int end = Length - 1;
        int start = 0;

        // Trim specified characters.
        if ((trimType & TrimType.Head) != 0)
        {
            for (start = 0; start < Length; start++)
            {
                int i = 0;
                char ch = this[start];
                for (i = 0; i < trimCharsLength; i++)
                {
                    if (trimChars[i] == ch)
                    {
                        break;
                    }
                }
                if (i == trimCharsLength)
                {
                    // The character is not in trimChars, so stop trimming.
                    break;
                }
            }
        }

        if ((trimType & TrimType.Tail) != 0)
        {
            for (end = Length - 1; end >= start; end--)
            {
                int i = 0;
                char ch = this[end];
                for (i = 0; i < trimCharsLength; i++)
                {
                    if (trimChars[i] == ch)
                    {
                        break;
                    }
                }
                if (i == trimCharsLength)
                {
                    // The character is not in trimChars, so stop trimming.
                    break;
                }
            }
        }

        return CreateTrimmedString(start, end);
    }

将它们组合在一起可能看起来像这样:

public static class TrimmerExtension
{
    public static string TrimWhitespaceAndPrefixes(this string str, params char[] trimChars)
    {
        var trimCharsLength = trimChars.Length;
        int start;
        for (start = 0; start < str.Length; start++)
        {
            var ch = str[start];
            if (!char.IsWhiteSpace(ch))
            {
                int i;
                for (i = 0; i < trimCharsLength; i++)
                {
                    if (trimChars[i] == ch)
                    {
                        break;
                    }
                }

                if (i == trimCharsLength)
                {
                    break;
                }
            }
        }

        return str[start..];
    }
}

如果性能不是很重要,我建议使用正则表达式或从https://stackoverflow.com/a/76133168/2770274开始的速记版本

Csharp相关问答推荐

C# uwp中的Win11启动屏幕剪辑工作方式不同

将修剪声明放入LINQ中

错误401未授权ASP.NET Core.使用JWT创建身份验证/授权

数组被内部函数租用时,如何将数组返回给ArrayPool?

. NET Core DB vs JSON模型设计

为什么将鼠标悬停在DateTimeOffset上只显示Hour值?

使用Audit.EntityFramework,我如何将外键的值设置为相关实体上的属性?

从依赖项容器在.NET 8中的Program.cs文件中添加IOC

取决于您的数据量的多个嵌套循环

.NET:从XPath定位原始XML文档中的 node

异步任务调用程序集

.NET 6:如何防止系统生成的日志(log)?

为什么ReadOnlySpan;T&>没有Slice(...)的重载接受Range实例的?

此异步方法在重写方法中缺少等待运算符警告

使用可空引用类型时C#接口实现错误

当我手动停止和关闭系统并打开时,Windows服务未启动

Linq SELECT的多条指令

C#中COM对象的实际地址

如何使用moq和xUnit对删除操作进行单元测试?

Avalonia MVVM数据模板