2015-03-28 4 views
1

Я делаю программу, которая должна просмотреть абзац текста и найти, сколько раз появляется определенное ключевое слово/ключевые слова. Он также должен выделять каждое из этих ключевых слов в тексте.Выделение ключевых слов в richtextbox в WPF

Мне удалось сделать его интерфейс, и теперь он может отслеживать, сколько раз слово появляется, но я действительно зациклился на том, как выделить, где появляются ключевые слова. Я выложу свой код ниже, любая помощь очень ценится в том, как искать и выделять текст внутри richtextbox. Поскольку это в WPF, явный richtextbox.find() не доступен для использования.

class TextAnalyser 
{ 
    public int FindNumberOfOccurances(List<string> keywords, string email) 
    { 
     int occurances = 0; 
     foreach (string keyword in keywords) 
     { 
      occurances += email.ToUpper().Split(new string[] { keyword.ToUpper() }, StringSplitOptions.None).Count() - 1; 
     } 
     return occurances; 
    } 

    public void TurnTextRed(List<string> keywords, string email, RichTextBox TextBox) 
    { 
     foreach(string keyword in keywords) 
     { 
     } 
    } 

    public List<string> ConvertTextToList(string text) 
    { 
     char[] splitChars = {}; 
     string[] ArrayText = text.Split(splitChars, StringSplitOptions.RemoveEmptyEntries); 
     return ArrayText.ToList<string>(); 
    } 

    public string GetStringFromTextBox(RichTextBox TextBox) 
    { 
     var textRange = new TextRange(
      TextBox.Document.ContentStart, 
      TextBox.Document.ContentEnd 
     ); 
     return textRange.Text; 
    } 
} 

И вот мое главное окно

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void AnalyseButton_Click(object sender, RoutedEventArgs e) 
    { 
     var textTool = new TextAnalyser(); 
     var keyWords = textTool.ConvertTextToList(textTool.GetStringFromTextBox(WordTextBox).Trim()); 
     var email = textTool.GetStringFromTextBox(EmailTextBox).Trim(); 
     int usesOfWord = textTool.FindNumberOfOccurances(keyWords, email); 
     Occurances.Text = usesOfWord.ToString(); 
    } 
} 

ответ

5

Вот метод используется, чтобы получить все слова в документе RichTextBox в.

public static IEnumerable<TextRange> GetAllWordRanges(FlowDocument document) 
    { 
     string pattern = @"[^\W\d](\w|[-']{1,2}(?=\w))*"; 
     TextPointer pointer = document.ContentStart; 
     while (pointer != null) 
     { 
      if (pointer.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text) 
      { 
       string textRun = pointer.GetTextInRun(LogicalDirection.Forward); 
       MatchCollection matches = Regex.Matches(textRun, pattern); 
       foreach (Match match in matches) 
       { 
        int startIndex = match.Index; 
        int length = match.Length; 
        TextPointer start = pointer.GetPositionAtOffset(startIndex); 
        TextPointer end = start.GetPositionAtOffset(length); 
        yield return new TextRange(start, end); 
       } 
      } 

      pointer = pointer.GetNextContextPosition(LogicalDirection.Forward); 
     } 
    } 

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

Наконец, легко выделить ваши слова.

IEnumerable<TextRange> wordRanges = GetAllWordRanges(RichTextBox.Document); 
     foreach (TextRange wordRange in wordRanges) 
     { 
      if (wordRange.Text == "keyword") 
      { 
       wordRange.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Red); 
      } 
     } 
+0

Большое спасибо приятелю, хороший ответ Ваш было много помощи – Needham

+0

краткий вопрос, что именно делает рисунок сделать в этом – Needham

+0

, как и его назначение, когда вы используете его в методе регулярного выражения – Needham

3

Произошла необходимость в этом и не могла найти подходящих решений. (Использование TextBox для привязки, выделения на лету, нескольких обращений и цветов и т. Д.). Это, очевидно, может быть расширено в соответствии с вашими потребностями. Это ссылается на пару методов расширения, которые добавляют/удаляют украшения указанного типа T из слоя aditorner UIElement.

Методы
public class HighlightRule 
{ 
    public SolidColorBrush Brush { get; set; } 
    public string MatchText { get; set; } 
    public HighlightRule(SolidColorBrush solidColorBrush, string matchText) 
    { 
     Brush = solidColorBrush; 
     MatchText = matchText; 
    } 
    public HighlightRule(Color color, string matchText) 
    { 
     Brush = new SolidColorBrush(color); 
     MatchText = matchText; 
    } 
    public HighlightRule() 
    { 
     MatchText = null; 
     Brush = Brushes.Black; 
    } 
} 
public class HighlightTextBox : TextBox 
{ 
    public List<HighlightRule> HighlightRules 
    { 
     get { return (List<HighlightRule>)GetValue(HighlightRulesProperty); } 
     set { SetValue(HighlightRulesProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for HighlightRules. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty HighlightRulesProperty = 
     DependencyProperty.Register("HighlightRules", typeof(List<HighlightRule>), typeof(HighlightTextBox), new FrameworkPropertyMetadata(new List<HighlightRule>(), new PropertyChangedCallback(HighlightRulesChanged))); 

    private static void HighlightRulesChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     HighlightTextBox tb = (HighlightTextBox)sender; 
     tb.ApplyHighlights(); 
    } 

    public HighlightTextBox() : base() 
    { 
     this.Loaded += HighlightTextBox_Loaded; 
    } 
    protected override void OnTextChanged(TextChangedEventArgs e) 
    { 
     base.OnTextChanged(e); 
     ApplyHighlights(); 
    } 
    private void HighlightTextBox_Loaded(object sender, RoutedEventArgs e) 
    { 
     ApplyHighlights(); 
    } 

    static HighlightTextBox() 
    { 
    } 
    public override void OnApplyTemplate() 
    { 
     base.OnApplyTemplate(); 
    } 

    public void ApplyHighlights() 
    { 

     this.TryRemoveAdorner<GenericAdorner>(); 
     foreach(HighlightRule rule in HighlightRules) 
     { 
      if (!string.IsNullOrEmpty(rule.MatchText) && !string.IsNullOrEmpty(Text) && 
       Text.ToLower().Contains(rule.MatchText.ToLower())) 
      { 
       if (base.ActualHeight != 0 && base.ActualWidth != 0) 
       { 
        int indexOf = 0; 
        do 
        { 
         indexOf = Text.IndexOf(rule.MatchText, indexOf); 
         if (indexOf == -1) break; 
         Rect rect = base.GetRectFromCharacterIndex(indexOf); 
         Rect backRect = base.GetRectFromCharacterIndex(indexOf + rule.MatchText.Length - 1, true); 
         this.TryAddAdorner<GenericAdorner>(new GenericAdorner(this, new Rectangle() 
         { Height = rect.Height, Width = backRect.X - rect.X, Fill = rule.Brush, Opacity = 0.5 })); 
         indexOf++; 
        } while (true); 

       } 
      } 
     } 

    } 

} 

GenericAdorner/Помощник

public class GenericAdorner : Adorner 
{ 
    private readonly UIElement adorner; 
    private readonly Point point; 
    public GenericAdorner(UIElement targetElement, UIElement adorner, Point point) : base(targetElement) 
    { 
     this.adorner = adorner; 
     if (adorner != null) 
     { 
      AddVisualChild(adorner); 
     } 
     this.point = point; 
    } 
    protected override int VisualChildrenCount 
    { 
     get { return adorner == null ? 0 : 1; } 
    } 
    protected override Size ArrangeOverride(Size finalSize) 
    { 
     if (adorner != null) 
     { 
      adorner.Arrange(new Rect(point, adorner.DesiredSize)); 
     } 
     return finalSize; 
    } 
    protected override Visual GetVisualChild(int index) 
    { 
     if (index == 0 && adorner != null) 
     { 
      return adorner; 
     } 
     return base.GetVisualChild(index); 
    } 
} 
public static void TryRemoveAdorner<T>(this UIElement element) 
     where T:Adorner 
    { 
     AdornerLayer layer = AdornerLayer.GetAdornerLayer(element); 
     if (layer != null) 
      layer.RemoveAdorners<T>(element); 
    } 
    public static void RemoveAdorners<T>(this AdornerLayer layer, UIElement element) 
     where T : Adorner 
    { 
     var adorners = layer.GetAdorners(element); 
     if (adorners == null) return; 
     for (int i = adorners.Length -1; i >= 0; i--) 
     { 
      if (adorners[i] is T) 
       layer.Remove(adorners[i]); 
     } 
    } 
    public static void TryAddAdorner<T>(this UIElement element, Adorner adorner) 
     where T: Adorner 
    { 
     AdornerLayer layer = AdornerLayer.GetAdornerLayer(element); 

     if (layer != null) 
      try 
      { 
       layer.Add(adorner); 
      } 
      catch (Exception) { } 
    } 
    public static bool HasAdorner<T>(this AdornerLayer layer, UIElement element) where T : Adorner 
    { 
     var adorners = layer.GetAdorners(element); 
     if (adorners == null) return false; 
     for (int i = adorners.Length - 1; i >= 0; i--) 
     { 
      if (adorners[i] is T) 
       return true; 
     } 
     return false; 
    } 
    public static void RemoveAdorners(this AdornerLayer layer, UIElement element) 
    { 
     var adorners = layer.GetAdorners(element); 
     if (adorners == null) return; 
     foreach (Adorner remove in adorners) 
      layer.Remove(remove); 
    } 

Часть XAML

<local:HighlightTextBox FontFamily="Calibri" Foreground="Blue" FontSize="12" Text="Hello you!! And also hello to you!" TextWrapping="Wrap" Margin="5,3,0,0"> 
    <local:HighlightTextBox.HighlightRules> 
     <local:HighlightRule Brush="Red" MatchText="you"/> 
     <local:HighlightRule Brush="Blue" MatchText="also"/> 
     </local:HighlightTextBox.HighlightRules> 
</local:HighlightTextBox> 

Внешний вид Highlight Example

+0

Код 'TryRemoveAdorner', который в соответствии с кодом на 'this' не компилируется. Наряду с «TryAddAdner» и «GenericAdorner». – OmegaMan

+0

Обновлен с запрошенным кодом. – JordanTDN

+0

Спасибо за обновление, все остальные ответы сосредоточены на 'TextBlock', ваш ответ был уникальным. – OmegaMan

Смежные вопросы