Каков наилучший способ обрезать все возможные пробельные символы ПЛЮС пользовательские символы с начала строки в С#?

В С# я хочу обрезать() оба конца строки всех возможных типов пробельных символов (как определено .IsWhitespace), а также обрезать начало строки, чтобы ТАКЖЕ удалить любой символ из пользовательского списка в 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() удалит из строки, поэтому я могу добавить его в список моих специальных символов префикса, которые будут удаленный?

Если на этот конкретный вопрос уже дан ответ, опубликуйте ссылку на вопрос и ответ(а).

Спасибо.

Вы ожидаете больше пробелов, чем CR, LF, TAB, SPACE? Почему бы не добавить их явно в список обрезки?

Hans Kesting 28.04.2023 22:36

Эффективность на самом деле не проблема, если вы вызываете Trim один раз, обрезав все символы, которые вам нужны. Если вам нужно что-то без распределения, потому что усеченное значение находится в стадии разработки, используйте Spans.

madreflection 28.04.2023 22:44

@Hans Kesting: строка поставляется из внешнего источника, над которым я не властен. Поэтому, хотя я обычно не ожидаю, что он будет содержать пробельные символы, кроме, скажем, TAB или SPACE, я не могу этого гарантировать.

Slim PICkins 28.04.2023 22:45

Вы можете написать небольшую программу, которая перебирает все значения char и печатает коды всех пробелов. Будем надеяться, что нет суррогатных пар, которые являются пробелами

Hans Kesting 28.04.2023 22:45

@madreflection «все символы, которые нужно обрезать». Правильно, но это вопрос. Как мне включить все пробельные символы, которые Trim обычно удаляет? Я не могу нигде найти окончательного списка; то есть либо массив char[], либо определение строки, включая все пробелы.

Slim PICkins 28.04.2023 22:48
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
5
88
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Почему бы не сделать это своими руками?

public static string MySpecialTrim(string str, char[] trimChars)
{
    for (var i = 0; i < str.Length; ++i)
    {
        char ch = str[i];
        if (!char.IsWhiteSpace(ch) && !trimChars.Contains(ch))              
            return str.Substring(i);
    }
    return str;
}

Таким образом, вы контролируете, какие символы обрезаются.

  • Вы можете использовать TrimStart().
  • Он удалит все начальные пробельные символы из текущей строки.
  • Вы также можете передать массив символов, который вы хотите удалить из начала строки.
  • например, вы хотите удалить пробел $ и проценты из строки, которую вы можете сделать, как показано ниже?
string input = "$%Hello World";

char[] trimChars = {' ', '$', '%'};

string output = input.TrimStart(trimChars);

Console.WriteLine(output); // Output: "Hello World"
  • Чтобы удалить из конца строки, вы можете использовать TrimEnd().

  • Для получения дополнительной информации о TrimStart и TrimEnd.

Да, они знают, что могут использовать TrimStart, но не могут, как объясняется в их вопросе под кодом.

Etienne de Martel 28.04.2023 22:53

Я так понимаю: char[] trimChars = {' ', '$', '%'}; строковый вывод = input.TrimStart (trimChars); удалит только указанные символы, и единственный символ пробела, который будет удален, - это просто сам пробел. Я считаю, что Trim() удаляет целое множество различных типов символов пробела, и я хотел бы, чтобы они ВСЕ были удалены от начала строки.

Slim PICkins 28.04.2023 22:55
Ответ принят как подходящий

Похоже, простого пути нет, так как 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

Спасибо, @Adassko. Я думаю, мне нужно написать собственный метод для итерации по строке, и похоже, что этот ответ (или что-то подобное) - это путь. Как я указал в своем вопросе, производительность МОЖЕТ быть проблемой, потому что исходный список строк для обработки может стать довольно большим.

Slim PICkins 28.04.2023 23:07

в этом случае я предлагаю также вернуть ReadOnlySpan<> вместо строки, это может дать большой прирост производительности, если вы продолжите обработку этих строк.

Adassko 28.04.2023 23:09

Я никогда раньше не слышал о Span<>, поэтому никогда им не пользовался. Я посмотрю на это. Спасибо!.

Slim PICkins 28.04.2023 23:10

Другие вопросы по теме