Создание умной функции обрезки строк в C # - PullRequest
10 голосов
/ 17 августа 2010

Я пытаюсь создать метод расширения строки, чтобы обрезать строку до определенной длины, но не прерывая слово. Я хотел проверить, есть ли что-то встроенное в фреймворк или более умный метод, чем мой. Вот мое (пока не проверено):

public static string SmartTrim(this string s, int length)
        {
            StringBuilder result = new StringBuilder();

            if (length >= 0)
            {
                if (s.IndexOf(' ') > 0)
                {
                    string[] words = s.Split(' ');
                    int index = 0;

                    while (index < words.Length - 1 && result.Length + words[index + 1].Length <= length)
                    {
                        result.Append(words[index]);
                        result.Append(" ");
                        index++;
                    }

                    if (result.Length > 0)
                    {
                        result.Remove(result.Length - 1, 1);
                    }
                }
                else
                {
                    result.Append(s.Substring(0, length));
                }
            }
            else
            {
                throw new ArgumentOutOfRangeException("length", "Value cannot be negative.");
            }

            return result.ToString();
        }

Ответы [ 7 ]

14 голосов
/ 17 августа 2010

Я бы использовал string.LastIndexOf - по крайней мере, если бы мы заботились только о пробелах. Тогда нет необходимости создавать какие-либо промежуточные строки ...

Пока не проверено:

public static string SmartTrim(this string text, int length)
{
    if (text == null)
    {
        throw new ArgumentNullException("text");
    }
    if (length < 0)
    {
        throw new ArgumentOutOfRangeException();
    }
    if (text.Length <= length)
    {
        return text;
    }
    int lastSpaceBeforeMax = text.LastIndexOf(' ', length);
    if (lastSpaceBeforeMax == -1)
    {
        // Perhaps define a strategy here? Could return empty string,
        // or the original
        throw new ArgumentException("Unable to trim word");
    }
    return text.Substring(0, lastSpaceBeforeMax);        
}

Тестовый код:

public class Test
{
    static void Main()
    {
        Console.WriteLine("'{0}'", "foo bar baz".SmartTrim(20));
        Console.WriteLine("'{0}'", "foo bar baz".SmartTrim(3));
        Console.WriteLine("'{0}'", "foo bar baz".SmartTrim(4));
        Console.WriteLine("'{0}'", "foo bar baz".SmartTrim(5));
        Console.WriteLine("'{0}'", "foo bar baz".SmartTrim(7));
    }
}

Результаты:

'foo bar baz'
'foo'
'foo'
'foo'
'foo bar'
2 голосов
/ 17 августа 2010

Попробуйте это.Он нулевой, не ломается, если длина длиннее строки, и требует меньше операций со строками.

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

public static string SmartTrim(this string s, int length)
{
    if(s == null || length < 0 || s.Length <= length)
        return s;

    // Edit a' la Jon Skeet. Removes unnecessary intermediate string. Thanks!
    // string temp = s.Length > length + 1 ? s.Remove(length+1) : s;
    int lastSpace = s.LastIndexOf(' ', length + 1);
    return lastSpace < 0 ? string.Empty : s.Remove(lastSpace);
}
2 голосов
/ 17 августа 2010

Как насчет решения на основе Regex? Возможно, вы захотите еще немного протестировать и проверить некоторые границы; но вот что приходит мне на ум:

using System;
using System.Text.RegularExpressions;

namespace Stackoverflow.Test
{
    static class Test
    {
        private static readonly Regex regWords = new Regex("\\w+", RegexOptions.Compiled);

        static void Main()
        {
            Console.WriteLine("The quick brown fox jumped over the lazy dog".SmartTrim(8));
            Console.WriteLine("The quick brown fox jumped over the lazy dog".SmartTrim(20));
            Console.WriteLine("Hello, I am attempting to build a string extension method to trim a string to a certain length but with not breaking a word. I wanted to check to see if there was anything built into the framework or a more clever method than mine".SmartTrim(100));
        }

        public static string SmartTrim(this string s, int length)
        {
            var matches = regWords.Matches(s);
            foreach (Match match in matches)
            {
                if (match.Index + match.Length > length)
                {
                    int ln = match.Index + match.Length > s.Length ? s.Length : match.Index + match.Length;
                    return s.Substring(0, ln);
                }
            }
            return s;
        }
    }
}
1 голос
/ 04 сентября 2015

Используйте вот так

var substring = source.GetSubstring(50, new string[] { " ", "." })

Этот метод может получить подстроку на основе одного или нескольких символов-разделителей

public static string GetSubstring(this string source, int length, params string[] options)
    {
        if (string.IsNullOrWhiteSpace(source))
        {
            return string.Empty;
        }

        if (source.Length <= length)
        {
            return source;
        }

        var indices =
            options.Select(
                separator => source.IndexOf(separator, length, StringComparison.CurrentCultureIgnoreCase))
                .Where(index => index >= 0)
                .ToList();

        if (indices.Count > 0)
        {
            return source.Substring(0, indices.Min());
        }

        return source;
    }
1 голос
/ 17 августа 2010

Обязательный LINQ на одну строку, если вас интересует только пробел в качестве границы слова:

return new String(s.TakeWhile((ch,idx) => (idx < length) || (idx >= length && !Char.IsWhiteSpace(ch))).ToArray());
1 голос
/ 17 августа 2010
string strTemp = "How are you doing today";
int nLength = 12;
strTemp = strTemp.Substring(0, strTemp.Substring(0, nLength).LastIndexOf(' '));

Я думаю, что должен это сделать.Когда я запустил это, в итоге получилось «Как дела».

Таким образом, ваша функция будет выглядеть так:длина целого не больше длины строки и не меньше 0.

0 голосов
/ 17 августа 2010

Я добавлю некоторые достоинства Linq, хотя другие ответили на это адекватно:

public string TrimString(string s, int maxLength)
{
    var pos = s.Select((c, idx) => new { Char = c, Pos = idx })
        .Where(item => char.IsWhiteSpace(item.Char) && item.Pos <= maxLength)
        .Select(item => item.Pos)
        .SingleOrDefault();

    return pos > 0 ? s.Substring(0, pos) : s;
}

Я не учел параметр, проверяющий, что другие просто подчеркивают важный код ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...