環境
- PHP 7.0
- PHPWord dev( この入れ方で入れました )
質問概要
既存docxを読み出すとdocxの中身が変なところで改行されて取得されるので、
それを回避したい。
質問詳細
解析するdocxファイルにもよるのですが、不規則に、docx上では1行で表示されている文章が二行や三行に分かれて取得されてしまいます。
やりたいこととしては、
(1)既存docx(任意)の読み込み
(2)特定文字列の置換&編集履歴の追加
(3)ダウンロード
なので、テンプレートは利用できません。
ひとまず、以下のようなコードを書きましたが、1行で見えるのに、
置換を行いたい文章が分かれて取得され、うまく置換ができません。
コード(ここに公開しているものと同じもの)
php
1<?php 2 3// 必要モジュールの読み込み 4require_once 'vendor/autoload.php'; 5 6use PhpOffice\PhpWord\Element\TrackChange; // 編集履歴系のクラス 7 8$search_word = 'パスワード'; 9$replace_word = 'バズワード'; 10 11// 読み込むファイルのパス 12$source = __DIR__ . '/base.docx'; 13 14// DOCXファイルの読み込み 15$phpWord = PhpOffice\PhpWord\IOFactory::load($source, 'Word2007'); 16 17// コピー先のdocx作成 18$phpWord_copy = new PhpOffice\PhpWord\PhpWord(); 19 20// 編集履歴系のクラスをインスタンス化 21$trackChangesView = new PhpOffice\PhpWord\ComplexType\TrackChangesView(); 22 23// 編集履歴記録開始 24$phpWord->getSettings()->setTrackRevisions(true); 25 26// セクションの取得 27$sections = $phpWord->getSections(); 28 29// セクションの分だけ、ぶん回せ 30foreach ($sections as $key => $value) { 31 32 // コピー先にセクションを追加 33 $section_copy = $phpWord_copy->addSection(); 34 35 // セクションの要素を全部取得 36 $sectionElement = $value->getElements(); 37 38 // 要素の分だけくーるくる 39 foreach ($sectionElement as $elementKey => $elementValue) { 40 41 // getTextメソッドを持っているか確認 → 持っていたら、それはテキスト情報なので置換対象 42 if (method_exists($elementValue, 'getText') === true) { 43 44 // 置換したりとか 45 makeTextData($elementValue, $section_copy, $search_word, $replace_word); 46 47 } else { 48 49 // テキストではない場合は、クラスによって処理を変える(無理やり感半端ない) 50 $class = get_class($elementValue); 51 52 switch ($class) { 53 54 // 改行の場合 55 case 'PhpOffice\PhpWord\Element\TextBreak': 56 // 改行を追加 57 $section_copy->addTextBreak(); 58 break; 59 60 // リッチテキストの場合 61 case 'PhpOffice\PhpWord\Element\TextRun': 62 // リッチテキストの中の要素全取得 63 getTextRunsTexts($elementValue, $section_copy, $search_word, $replace_word); 64 break; 65 66 } 67 68 } 69 70 71 } 72 73} 74 75 76// DOCXファイルに書き出し 77$objWriter = PhpOffice\PhpWord\IOFactory::createWriter($phpWord_copy, 'Word2007'); 78$objWriter->save('php_output.docx'); 79 80 81/** 82 * リッチテキストデータの中に含まれるテキストを抽出してセクションとして追加する 83 * 84 * @param $elementValue 85 * @param $section_copy 86 * @param $search_word 87 * @param $replace_word 88 */ 89function getTextRunsTexts(&$elementValue, &$section_copy, $search_word, $replace_word) 90{ 91 92 // リッチテキストの中の要素全取得 93 $sectionElement = $elementValue->getElements(); 94 95 // 回す 96 foreach ($sectionElement as $sectionElementKey => $sectionElementValue) { 97 98 // 純粋なテキストエリアの場合 99 if (method_exists($sectionElementValue, 'getText') === true) { 100 101 // 置換したりとか 102 makeTextData($sectionElementValue, $section_copy, $search_word, $replace_word); 103 104 } 105 106 } 107 108} 109 110 111/** 112 * テキストデータを作成して新しいdocxデータに追加していく 113 * 114 * @param $elementValue 115 * @param $section_copy 116 * @param $search_word 117 * @param $replace_word 118 */ 119function makeTextData(&$elementValue, &$section_copy, $search_word, $replace_word) 120{ 121 122 // テキスト取得 123 $text = htmlspecialchars($elementValue->getText()); 124 125 // テキストがスペースだけなら無視する(変に改行されるため) 126 if ($text === ' ') { 127 return; 128 } 129 130 // フォントスタイルの取得 131 $font_style = $elementValue->getFontStyle(); 132 133 // パラグラフスタイル(多分色とかそういうのやと思う)を取得 134 $paragraph_style = $elementValue->getParagraphStyle(); 135 136 // インデントがあるかの取得 137 $indent = $paragraph_style->getIndentation(); 138 139 // インデントがあれば、デザインがめっさ崩れるので 140 if ( method_exists($indent, 'getLeft') === true && $indent->getLeft() > 0 ){ 141 // 幅を小さくしてあげる 142 $indent->setLeft($indent->getLeft()/1000); 143 } 144 145 // 取得したテキストをコピー先に作成 146 $text_elem = $section_copy->addText($text, $font_style, $paragraph_style); 147 148 // 特定ワードで置換してみる 149 if (preg_match('/' . $search_word . '/', $text) === 1) { 150 151 // 置換 152 $text = str_replace($search_word, $replace_word, $text); 153 154 // デリートの変更履歴を設定 155 $text_elem->setChangeInfo(TrackChange::DELETED, 'Nな人'); 156 157 // 変更後のテキストを設定 158 $new_text = $section_copy->addText($text, $font_style, $paragraph_style); 159 160 // インサートの変更履歴を設定 161 $new_text->setChangeInfo(TrackChange::INSERTED, 'Nな人'); 162 163 } 164 165}
解決策として、
(1)docxから正常に文章を抽出
(2)文末かどうかを取得した文章からPHPで判断
と言うものがあげられるかと思うのですが、
どちらに対しても知識不足で案が出ません。
ご存じの方がいらっしゃいましたら、ご教示いただけますと幸いです。
よろしくお願いいたします。
あなたの回答
tips
プレビュー