Найти все новые строки в richtextbox - PullRequest
0 голосов
/ 11 октября 2018

Я работаю над пользовательским элементом управления texteditor и столкнулся с этой проблемой.

Мне нужна функция, которая получает символьные индексы для каждой новой строки "\ n" в тексте.У меня уже есть два способа добиться этого:

private List<int> GetNewLineLocations()
    {
        var list = new List<int>();
        int ix = 0;
        foreach (var c in this.Text)
        {
            if (c == '\n') list.Add(ix);
            ix++;
        }
        Debug.WriteLine(ix);
        return list;
    }

И:

private List<int> GetNewLineLocations()
    {
        var list = new List<int>();
        int ix = -1;

        for (int i = 0; i < this.Lines.Length; i++)
        {
            ix += Lines[i].Length;
            ix += 1;
            list.Add(ix);
        }

        return list;
    }

Первое решение работает, но замедляется, когда в richtextbox вводится больше текста, который составляет около 40000 символов.но это может быть разбросано по множеству строк, например 20000.

Второй кажется более быстрым, потому что он делает петли меньше и делает более или менее то же самое, но резко замедляется на 1000 строк, неважно насколькотекст, который они содержат.

Конечно, код должен работать быстро и не использовать много ресурсов, поэтому я подумал, что второе решение будет лучше.

Мой вопрос:

  1. Какое решение лучше и почему?

  2. Почему второе решение намного медленнее?

  3. Есть ли еще лучшее решение?

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

Я попробовал оба ваших примера, а также Феликса и мое собственное решение, используя расширенное текстовое поле и 40 тыс. Строк.В результате это было самым быстрым, и я не видел замедления.Можете ли вы попробовать передать массив строк в качестве параметра и сообщить нам результат?

public static List<int> GetNewLineLocations(this string[] lines)
        {
            var list = new List<int>();
            int ix = -1;

            for (int i = 0; i < lines.Length; i++)
            {
                ix += lines[i].Length+1;
                list.Add(ix);
            }

            return list;
        }
0 голосов
/ 11 октября 2018

При работе со строками Регулярные выражения очень удобны в использовании.Но они не самые быстрые.Если вам нужна более быстрая обработка, вы должны делать это на более низких уровнях и параллельно.И обязательно используйте long как index, потому что int позволяет обрабатывать только до 2 ^ 31 символов и long до 2 ^ 63 символов.

Я согласен с @ Nyerguds , который сказал в комментариях:

Проблема в том, что стандартная функция для извлечения текста в поле расширенного текста на самом делефункция обработки, которая должна отфильтровывать разметку RTF.Фактическая функция для извлечения текста - это узкое место, а не то, что следует за ним.

Таким образом, ваши данные должны храниться где-то в коде, а не в пользовательском интерфейсе.Рано или поздно при обработке длинных текстов, которые все равно будут вызывать проблемы, такие как заикание при прокрутке или дальнейшие узкие места.И я бы представлял только те строки, которые могли бы отображаться в элементе управления в любом случае.Таким образом, вы должны продумать дизайн приложения. Проверьте разделение между фронтом и бэкендом. Хранение данных в бэкэнде позволит вам напрямую получать доступ к данным, не завися от методов Textbox или другого пользовательского интерфейса.

Вот пример того, каклегко обрабатывать данные с помощью Parallel Class .net framework:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading.Tasks;

    namespace ConsoleApp1
    {
        internal class Program
        {
            public static byte[] _globalDataStore { get; set; }
            private static void Main(string[] args)
            {
                DoStuff();
                ShowDone();
            }

            private static void ShowDone()
            {
                Console.WriteLine("done...");
                Console.ReadKey();
            }

            private static void DoStuff()
            {
                var tempData = GetData();
                StoreData(ref tempData);
                tempData = null; //free some ram
                var dataIdentifier = (byte)'\n';
                GetAndPromptDataPositions(_globalDataStore, dataIdentifier);
            }

            private static void GetAndPromptDataPositions<T>(T[] data, T dataIdentifier)
            {
                var dataPositionList = GetDataPositions<T>(data, dataIdentifier);
                PromptDataPostions(dataPositionList);
            }

            private static void PromptDataPostions(IEnumerable<long> positionList)
            {
                foreach (var position in positionList)
                {
                    Console.WriteLine($"Position '{position}'");
                }
            }
            private static string GetData()
            {
                return "aasdlj\naksdlkajsdlkasldj\nasld\njkalskdjasldjlasd";
            }

            private static void StoreData(ref string tempData)
            {
                _globalDataStore = Encoding.ASCII.GetBytes(tempData);
            }

            private static List<long> GetDataPositions<T>(T[] data, T dataToFind)
            {
                lock (data) //prevent data from being changed while processing, important when have other threaded could write data 
                {
                    var postitonList = new List<long>();
                    Parallel.For(0, data.LongLength, (position) =>
                    {
                        if (data[position].Equals(dataToFind))
                        {
                            lock (postitonList) //lock list because of multithreaded access to prevent data corruption
                            {
                                postitonList.Add(position);
                            }
                        }
                    });
                    return postitonList;
                }
            }
        }
    }
...