質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Word

Microsoft WordはMicrosoftが開発した業務用の文書生成用のソフトウェアです。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

0回答

926閲覧

【PHPWord】docxの中身が変なところで改行されて取得される

nnahito

総合スコア2004

Word

Microsoft WordはMicrosoftが開発した業務用の文書生成用のソフトウェアです。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2018/03/19 09:59

環境

質問概要

既存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で判断
と言うものがあげられるかと思うのですが、
どちらに対しても知識不足で案が出ません。

ご存じの方がいらっしゃいましたら、ご教示いただけますと幸いです。
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問