微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Textpointer GetTextInRun,在ö,ü或/和ä

如何解决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”。然后运行英语拼写检查。你会看到一个错误。视觉上一切都是一样的。但是一个词会被分成三个RunMS Word 将检测来自另一种语言的字母并报告错误。

这个问题描述的问题很可能是输入 语。请参阅以下描述类似问题的帖子:Edit RichTextBox Run element without splitting into multiple Run elements

解决方案 1:

尝试在 RichTextBox 控件中设置输入语言。例如,德语:

<RichTextBox x:Name="rtb" Language="de-de">
</RichTextBox>

支持的文化代码 https://docs.microsoft.com/en-us/bingmaps/rest-services/common-parameters-and-types/supported-culture-codes

解决方案 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;
        }
    }
}

使用上面的代码或用于测试目的:

  1. FindWordsAsync() 方法中,用要在文档中找到的词填充 pairs。如果找到的话,设置一些颜色以用于更改单词的前景。但很可能您不需要此用于测试的功能,因此您应该更改代码以仅保留所需单词的列表。
  2. List<KeyValuePair<string,IList<string> words) 方法使用正则表达式来查找定义的单词。因此,此方法的一部分可以根据文档中的文本搜索条件进行更改。

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?