如何解决Textpointer GetTextInRun,在ö,ü或/和ä
我尝试在rtf中找到一个字符串(占位符)(标记并稍后替换)。它可以工作,但是如果有“ö”,“ä”,“ü” GetTextInRun可以将其分为两个或更多部分
TextRange text = new TextRange(rtb.Document.ContentStart,rtb.Document.ContentEnd);
TextPointer current = text.Start.GetInsertionPosition(LogicalDirection.Forward);
while (current != null)
{
string textInRun = current.GetTextInRun(LogicalDirection.Forward);
...
}
MSDN的意思是:“此方法仅返回文本的不间断运行。如果除Text以外的任何符号类型在指定方向上与当前TextPointer相邻,则不返回任何内容。类似地,仅返回直到下一个非文本的文本符号。”
那么öüä不是“文字”吗?但是为什么第二部分的结果不是“ä”而是“äöü”
占位符看起来像这样:“ [[tabletyp1的$ [TabelleTyp1_test]]”(一直有效),但可以是“ [[$ TabelleTyp1_1.HalloüchbinänÜmlütöst]]”(失败,textinRun:“ [[$ TabelleTyp1_1。“您好”-但是在rtf文件中的每次更改之后,结果也都会更改(“ [[$ TabelleTyp1_1。“”),因此,我认为必须有一个不可见的char来破坏“文本”,如果öäü在文本里面吗?但是我不知道如何在不丢失Textpointer的情况下忽略或删除这个(随机?)字符。
顺便说一句:正则表达式的“检测”没有任何问题,因此它不能成为“隐藏”字符吗? regex:@“ [[[$ TabelleTyp1_ [a-zA-Z0-9äöü。] *]]”)); 唯一的区别是:对于正则表达式,我使用表单richtextBox,用于选择/替换xceedrichttextBox(wpf)
编辑:我将text.Text复制到剪贴板,并寻找隐藏的字符..没有隐藏的字符,只有CR / LF在行尾。
Edit2:“。”是错误的,只有ö,ä和ü
解决方法
我认为段落中的文本分成不同部分的原因只有一个 - 上下文变化。当用户更改以下特征之一时会发生这种情况:
- 输入语言
- 字体名称
- 字体样式
- 前景色
- 背景颜色等
我不考虑可以以编程方式进行分区的情况。
顺便说一下,在 MS Office Word 中很容易重现这个问题。只需用英语输入单词 “test”,然后用另一种语言(例如德语)替换字母 “e”。然后运行英语拼写检查。你会看到一个错误。视觉上一切都是一样的。但是一个词会被分成三个Run
。 MS Word 将检测来自另一种语言的字母并报告错误。
这个问题描述的问题很可能是输入 语。请参阅以下描述类似问题的帖子:Edit RichTextBox Run element without splitting into multiple Run elements。
解决方案 1:
尝试在 RichTextBox
控件中设置输入语言。例如,德语:
<RichTextBox x:Name="rtb" Language="de-de">
</RichTextBox>
解决方案 2:
如果由于某些原因 RTF 文档已经包含拆分为不同 Run
的特定词,则有必要使用上下文相关的方法来解析/分析 RichTextBox
内容。
下面的例子展示了它是如何实现的。
MainWindow.xaml:
<Window ...
Title="MainWindow" Height="350" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<RichTextBox Name="rtb" BorderBrush="{x:Null}" Padding="5" Margin="10"
VerticalScrollBarVisibility="Auto">
<FlowDocument>
<Paragraph>
<Run>Paste some document for testing and press the button below</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
<Button Grid.Row="1" Click="Button_SearchAsync" Margin="2" Padding="3">Press to search</Button>
</Grid>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace WpfApp17
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void Button_SearchAsync(object sender,RoutedEventArgs e)
{
await FindWordsAsync(rtb);
rtb.Focus();
}
public async Task FindWordsAsync(RichTextBox rtb)
{
await Task<object>.Factory.StartNew(() =>
{
var pairs = new Dictionary<string,SolidColorBrush>(StringComparer.InvariantCultureIgnoreCase)
{
{ "Rückvergrößerungsgeräten",Brushes.Blue },{ "Rückvergrößerungsgeräte",Brushes.DarkOrange },{ "Rückvergrößerungsgerät",Brushes.Red }
};
IList<KeyValuePair<string,TextRange>> ranges = null;
this.Dispatcher.Invoke(() =>
{
// Define the range to be used to analyze for the specified words
var textRange = new TextRange(rtb.Document.ContentStart,rtb.Document.ContentEnd);
// Build list of Word/TextRange pairs
ranges = textRange.CalculateTextRange(pairs.Select(d => d.Key).ToList());
});
// Color words by using calculated `TextRange`.
for (int i = 0; i < ranges.Count; i++)
{
this.Dispatcher.Invoke(() => { ranges[i].Value.ApplyPropertyValue(TextElement.ForegroundProperty,pairs[ranges[i].Key]); });
//list[i].Value.ApplyPropertyValue(TextElement.FontSizeProperty,20.0);
}
return Task.FromResult<object>(null);
});
}
}
}
TextRangeExt.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Documents;
namespace WpfApp17
{
public static class TextRangeExt
{
public static IList<KeyValuePair<string,TextRange>> CalculateTextRange(this TextRange range,IList<string> words)
{
// Building the regular expression pattern
var pattern = new StringBuilder(@"\b");
for (int i = 0; i < words.Count; i++)
{
if (i > 0) pattern.Append('|');
pattern.Append(words[i]);
}
pattern.Append(@"\b");
var regExp = new Regex(pattern.ToString(),RegexOptions.IgnoreCase);
int correction = 0;
var result = new List<KeyValuePair<string,TextRange>>();
TextPointer start = range.Start;
// Enumerate all found mathes and creating list of Word/TextRange pairs
foreach (Match match in regExp.Matches(range.Text))
{
if (CalculateTextRange(start,match.Index - correction,match.Length) is TextRange tr)
{
result.Add(new KeyValuePair<string,TextRange>(match.Value,tr));
correction = match.Index + match.Length;
start = tr.End;
}
}
return result;
}
// Return calculated a `TextRange` of the string started from `iStart` index
// and having `length` size or `null`.
public static TextRange CalculateTextRange(TextPointer startSearch,int iStart,int length)
{
return (startSearch.GetTextPositionAtOffset(iStart) is TextPointer start)
? new TextRange(start,start.GetTextPositionAtOffset(length))
: null;
}
public static TextPointer GetTextPositionAtOffset(this TextPointer position,int offset)
{
for (TextPointer current = position; current != null; current = position.GetNextContextPosition(LogicalDirection.Forward))
{
position = current;
var adjacent = position.GetAdjacentElement(LogicalDirection.Forward);
var navigator = position.GetPointerContext(LogicalDirection.Forward);
switch (navigator)
{
case TextPointerContext.Text:
int count = position.GetTextRunLength(LogicalDirection.Forward);
if (offset <= count) return position.GetPositionAtOffset(offset);
offset -= count;
break;
case TextPointerContext.ElementStart:
if (adjacent is InlineUIContainer)
{
offset--;
}
else if (adjacent is ListItem lsItem)
{
var index = new TextRange(lsItem.ElementStart,lsItem.ElementEnd).Text.IndexOf('\t');
if (index >= 0) offset -= index + 1;
}
break;
case TextPointerContext.ElementEnd:
if (adjacent is Paragraph para)
{
var correction = 0;
if (para.Parent is TableCell tcell)
{
var bCount = tcell.Blocks.Count;
var cellText = new TextRange(tcell.Blocks.FirstBlock.ContentStart,tcell.Blocks.LastBlock.ContentEnd).Text;
if ((bCount == 1 && cellText.EndsWith(Environment.NewLine)) || bCount > 1)
{
correction = 2;
}
else if (tcell.Parent is TableRow trow)
{
var cells = trow.Cells.Count;
correction = (cells <= 0 || trow.Cells.IndexOf(tcell) != cells - 1) ? 1 : 2;
}
}
else
{
correction = 2;
}
offset -= correction;
}
break;
}
}
return position;
}
}
}
使用上面的代码或用于测试目的:
- 在
FindWordsAsync()
方法中,用要在文档中找到的词填充pairs
。如果找到的话,设置一些颜色以用于更改单词的前景。但很可能您不需要此用于测试的功能,因此您应该更改代码以仅保留所需单词的列表。 -
List<KeyValuePair<string,IList<string> words)
方法使用正则表达式来查找定义的单词。因此,此方法的一部分可以根据文档中的文本搜索条件进行更改。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。