如何用Ruby将带格式标记的纯文本转换为指定格式的Docx?
Hey there! Great question—since you already have Ruby generating your core content as TXT, adding format markers and converting to DOCX is totally straightforward. Here are two solid approaches tailored to your needs:
Option 1: Use Markdown as Your Formatting Marker Language
Markdown is perfect here because it has built-in syntax for exactly the styles you need (bold, italic, indentation, lists) and there are robust Ruby libraries to parse it into DOCX.
Step 1: Generate TXT with Markdown Syntax
When building your output TXT, use standard Markdown tags:
- Bold text: Wrap with
**double asterisks** - Italic text: Wrap with
*single asterisks* - Indented/block quote text: Prefix with
> - Bulleted lists: Start lines with
-
Example TXT content (after parameter replacement):
**Contract ID**: C-2024-{{client_id}} *Effective Date*: {{date}} > Core Terms: - Client Responsibility: {{client_duty}} - Vendor Responsibility: {{vendor_duty}}
Step 2: Ruby Code to Convert Markdown TXT to DOCX
Use the ruby-docx gem for DOCX manipulation and commonmarker for parsing Markdown.
First install the gems:
gem install ruby-docx commonmarker
Then the code:
require 'docx' require 'commonmarker' # Load your generated parameterized TXT raw_content = File.read('output_content.txt') # Parse Markdown into an abstract syntax tree (AST) for easy processing markdown_doc = Commonmarker.render_doc(raw_content, :DEFAULT) # Initialize a new DOCX document docx = Docx::Document.new # Traverse the Markdown AST and map nodes to DOCX styles markdown_doc.walk do |node| case node.type when :paragraph para = docx.add_paragraph node.each_child do |child| next unless child.type == :text # Apply bold/italic based on parent node type style = {} style[:bold] = true if child.parent.type == :strong style[:italic] = true if child.parent.type == :emph para.add_run(child.string_content, style) end when :list_item para = docx.add_paragraph # Add 0.5-inch left indent (DOCX uses twips: 1 inch = 1440 twips) para.indentation.left = 72 node.each_child do |child| para.add_run("- #{child.string_content}") if child.type == :text end when :block_quote para = docx.add_paragraph # Add 1-inch left indent for block quotes para.indentation.left = 144 node.each_child do |child| para.add_run(child.string_content) if child.type == :text end end end # Save the final styled DOCX docx.save('final_contract.docx')
Option 2: Custom Formatting Markers (For Unique Needs)
If you need full control over custom tags (instead of using Markdown), define your own simple markers and use regex to map them to DOCX styles.
Step 1: Generate TXT with Custom Markers
Example custom tags:
- Bold:
{{b}}your text{{/b}} - Italic:
{{i}}your text{{/i}} - Indented text:
{{indent}}your text{{/indent}}
Step 2: Ruby Code to Process Custom Markers
require 'docx' raw_content = File.read('output_content.txt') docx = Docx::Document.new # Split content into paragraphs (double newlines as separators) raw_content.split("\n\n").each do |para_text| para = docx.add_paragraph # Process bold tags first para_text.gsub!(/({{b}})(.*?)({{\/b}})/) do para.add_run($2, bold: true) '' # Clear the matched tag to avoid duplicate text end # Process italic tags para_text.gsub!(/({{i}})(.*?)({{\/i}})/) do para.add_run($2, italic: true) '' end # Process indent tags if para_text.match?(/{{indent}}(.*?){{\/indent}}/) para.indentation.left = 72 para_text = para_text.gsub(/{{indent}}(.*?){{\/indent}}/, '\1') end # Add any remaining plain text to the paragraph para.add_run(para_text) unless para_text.empty? end docx.save('final_contract.docx')
Recommendation
Stick with Markdown if possible—it's a standard, well-documented syntax that reduces the need to maintain custom regex. The commonmarker library handles edge cases (like nested styles) far better than custom code would.
内容的提问来源于stack exchange,提问作者Andres Pérez

