在 richtextbox 中查找所有换行符
Find all newlines in richtextbox
我正在开发自定义文本编辑器控件并遇到了这个问题。
我需要一个函数来获取文本中每个换行符“\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 行时速度显着降低,无论它们包含多少文本。
代码当然需要 运行 快速并且不使用大量资源,这就是为什么我认为第二个解决方案会更好。
我的问题是:
哪个解决方案更好,为什么?
为什么第二个解决方案这么慢?
还有更好的解决方案吗?
使用字符串时 Regular Expressions 非常好用。但它们并不是最快的。如果您需要更快的处理速度,您应该在较低级别并行进行。并确保使用 long 作为索引,因为 int 最多只允许您处理 2^31 个字符,而 long 最多可处理 2^63 个字符。
我同意@Nyerguds
谁在评论中说:
The problem is that the standard function to fetch the text in a rich text box is actually a processing function that has to filter out the RTF markup. The actual function to fetch the text is the bottleneck, not what comes after it.
所以您的数据应该保存在代码中的某个位置,而不是在用户界面中。处理长文本迟早会引起麻烦,例如滚动时卡顿或进一步的瓶颈。而且我只会代表可以在控件中显示的行。所以你应该仔细考虑你的应用程序设计。 Check your Front/Backend seperation. 将您的数据存储在后端将允许您直接访问您的数据,而不依赖于您的文本框方法或其他用户界面内容。
以下是如何使用 .net 框架的 Parallel Class 轻松处理数据的示例:
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;
}
}
}
}
我尝试了您的示例和 Felix 的示例以及我自己使用富文本框和 40k 行的解决方案。结果是这是最快的,而且我没有看到减速。您能否尝试将行数组作为参数传递并让我们知道结果?
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;
}
我正在开发自定义文本编辑器控件并遇到了这个问题。
我需要一个函数来获取文本中每个换行符“\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 行时速度显着降低,无论它们包含多少文本。
代码当然需要 运行 快速并且不使用大量资源,这就是为什么我认为第二个解决方案会更好。
我的问题是:
哪个解决方案更好,为什么?
为什么第二个解决方案这么慢?
还有更好的解决方案吗?
使用字符串时 Regular Expressions 非常好用。但它们并不是最快的。如果您需要更快的处理速度,您应该在较低级别并行进行。并确保使用 long 作为索引,因为 int 最多只允许您处理 2^31 个字符,而 long 最多可处理 2^63 个字符。
我同意@Nyerguds 谁在评论中说:
The problem is that the standard function to fetch the text in a rich text box is actually a processing function that has to filter out the RTF markup. The actual function to fetch the text is the bottleneck, not what comes after it.
所以您的数据应该保存在代码中的某个位置,而不是在用户界面中。处理长文本迟早会引起麻烦,例如滚动时卡顿或进一步的瓶颈。而且我只会代表可以在控件中显示的行。所以你应该仔细考虑你的应用程序设计。 Check your Front/Backend seperation. 将您的数据存储在后端将允许您直接访问您的数据,而不依赖于您的文本框方法或其他用户界面内容。
以下是如何使用 .net 框架的 Parallel Class 轻松处理数据的示例:
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;
}
}
}
}
我尝试了您的示例和 Felix 的示例以及我自己使用富文本框和 40k 行的解决方案。结果是这是最快的,而且我没有看到减速。您能否尝试将行数组作为参数传递并让我们知道结果?
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;
}