Skip to main content

linch_docx_rs/document/
text_ops.rs

1//! Text search and replace operations for Document
2
3use crate::document::{BlockContent, Document, Paragraph, ParagraphContent, RunContent};
4
5/// Text location in the document
6#[derive(Clone, Debug)]
7pub struct TextLocation {
8    pub paragraph_index: usize,
9    pub char_offset: usize,
10}
11
12impl Document {
13    /// Replace text across all paragraphs. Returns number of replacements.
14    pub fn replace_text(&mut self, find: &str, replace: &str) -> usize {
15        let mut count = 0;
16        for content in &mut self.body.content {
17            if let BlockContent::Paragraph(para) = content {
18                count += replace_text_in_paragraph(para, find, replace);
19            }
20        }
21        count
22    }
23
24    /// Find text locations across all paragraphs
25    pub fn find_text(&self, needle: &str) -> Vec<TextLocation> {
26        let mut results = Vec::new();
27        for (para_idx, para) in self.body.paragraphs().enumerate() {
28            let text = para.text();
29            let mut start = 0;
30            while let Some(pos) = text[start..].find(needle) {
31                results.push(TextLocation {
32                    paragraph_index: para_idx,
33                    char_offset: start + pos,
34                });
35                start += pos + needle.len();
36            }
37        }
38        results
39    }
40}
41
42/// Replace text in a paragraph's runs
43fn replace_text_in_paragraph(para: &mut Paragraph, find: &str, replace: &str) -> usize {
44    let mut count = 0;
45    for content in &mut para.content {
46        if let ParagraphContent::Run(run) = content {
47            for rc in &mut run.content {
48                if let RunContent::Text(ref mut text) = rc {
49                    let matches = text.matches(find).count();
50                    if matches > 0 {
51                        *text = text.replace(find, replace);
52                        count += matches;
53                    }
54                }
55            }
56        }
57    }
58    count
59}