rtf-parser
| Language | Rust |
|---|---|
| License | MIT |
| Repository | github.com/d0rianb/rtf-parser |
| Documentation | docs.rs/rtf-parser |
| Depends on | serde (optional wasm-bindgen and tsify for the WebAssembly build) |
| Read / write | reads RTF; doesn't write RTF |
rtf-parser has two stages. Lexer::scan turns RTF text into a Vec<Token> (control words, groups, plain text), and Parser::new(tokens).parse() builds an RtfDocument:
header:RtfHeaderwithcharacter_set,code_page,font_table(aHashMapfrom font number toFont { name, character_set, font_family }),color_tableandstylesheet.body:Vec<StyleBlock>, each withtext, apainter(font, size, color, bold, italic, underline, strike, superscript, subscript, small caps) and aparagraph(alignment, spacing, indentation, tab width).
It implements RTF 1.9 with UTF-16 \uN escapes and special characters (dashes, quotes). Known gaps: \bin binary data isn’t supported and can break lexing, and tables and pictures aren’t modeled. Errors are returned as LexerError or ParserError.
Installation#
Shell
cargo add rtf-parser
Basic usage: extract text from an RTF file#
Rust
use rtf_parser::RtfDocument;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let doc = RtfDocument::from_filepath("letter.rtf")?;
println!("{}", doc.get_text());
Ok(())
}
RtfDocument also implements TryFrom<&str>, TryFrom<String> and TryFrom<&mut File>.
How to parse an RTF string step by step#
Rust
use rtf_parser::{Lexer, Parser};
let rtf = r#"{\rtf1\ansi{\fonttbl\f0\fswiss Helvetica;}\f0\pard Some {\b bold} text.\par}"#;
let tokens = Lexer::scan(rtf)?;
let doc = Parser::new(tokens).parse()?;
for block in &doc.body {
println!("{:?} bold={} {:?}", block.text, block.painter.bold, block.paragraph.alignment);
}
How to read fonts and colors#
Rust
for (num, font) in &doc.header.font_table {
println!("f{num}: {} ({:?})", font.name, font.font_family);
}
for (num, c) in &doc.header.color_table {
println!("color {num}: #{:02x}{:02x}{:02x}", c.red, c.green, c.blue);
}
How to convert to simple HTML#
Rust
fn to_html(doc: &rtf_parser::RtfDocument) -> String {
let mut out = String::from("<p>");
for block in &doc.body {
let mut t = block.text.replace('&', "&").replace('<', "<").replace('\n', "</p>\n<p>");
if block.painter.bold { t = format!("<b>{t}</b>"); }
if block.painter.italic { t = format!("<i>{t}</i>"); }
if block.painter.underline { t = format!("<u>{t}</u>"); }
out.push_str(&t);
}
out.push_str("</p>");
out
}
Tips#
font_sizein the painter is in half-points, as in RTF (24= 12 pt).- All document structs implement serde’s
Serialize, soserde_json::to_string(&doc)gives a JSON dump for debugging. - For JavaScript, the same parser is published to npm as
rtf-parser-wasmwith aparse_rtffunction.