あなたのシナリオには多くのエッジケースがあり、言葉が一番上に追加されています。クラシックをやりたいと思っていると思いますが、今回は親(または他のブロック要素)内でも同様に、ダブルブレークで新しい段落を開始します。<div>
ほとんどの作業は HTML パーサーに任せますが、それでもテキスト検索と置換 (xpath の隣) を使用します。したがって、今後表示されるのは少しハックですが、かなり安定していると思います。
まず、上記の div の最上位または子であるすべてのテキスト ノードを選択します。
(.|./div)/text()
この xpath は、 にロードされたときに HTML フラグメントのルート タグを表すタグであるアンカー要素に相対的です。<body>
DOMDocument
div の子の場合、開始段落を最初に挿入します。
次に、いずれにせよ、新しい段落を開始するシーケンスが出現するたびにブレークマーク(ここではコメントの形式で)を挿入します("\n\n"
これは空白の正規化のためであるはずです。間違っている可能性があり、それが適用されない場合、これを透過的に機能させるには、事前に空白の正規化を行う必要があります)。
/* @var $result DOMText[] */
$result = $xp->query('(.|./div)/text()', $anchor);
foreach ($result as $i => $node)
{
if ($node->parentNode->tagName == 'div')
{
$insertBreakMarkBefore($node, true);
}
while (FALSE !== $pos = strpos($node->data, $paragraphSequence))
{
$node = $node->splitText($pos + $paragraphSequenceLength);
$insertBreakMarkBefore($node);
}
}
<p>
これらの挿入されたブレーク マークは、HTMLタグに置き換えられるだけです。HTML パーサーはそれらを適切な<p>...</p>
ペアに変換するので、そのアルゴリズムを書く手間を省くことができます (これは興味深いかもしれませんが)。これは基本的に、他の回答で概説したように機能しますが、リンクが見つかりません。
- DOM ツリーの変更後、再度内部 HTML を取得します
<body>
。
- セット マークを次のように置き換えます
"<p>"
(ここでは、クラスにもマークを付けて、これを表示します)
<p>...</p>
HTML フラグメントをパーサーに再度ロードして、適切なペアで DOM を再作成します。
DOMDocument
パーサーから HTML を再度取得します。
これらは、コード内の手順の概要を示しています (関数定義の一部を少しスキップします)。
$needle = sprintf('%1$s<!--%2$s-->%1$s', $paragraphSequence, $paragraphComment);
$replace = sprintf("\n<p class=\"%s\">\n", $paragraphComment);
$html = strtr($innerHTML($anchor), array($needle . $needle => $replace, $needle => $replace));
echo "HTML afterwards:\n", $innerHTML($loadHTMLFragment($html));
これが示すように、2 つのシーケンスが 1 つのシーケンスに置き換えられます。おそらく最後の 1 つも削除する必要があります (該当する場合は、ここで空白を削除することもできます)。
最終的な HTML 出力:
<div>
<p class="break">
This text should be wrapped in a p tag.
</p>
</div>
<p class="break">
This also should be wrapped.
</p>
<p class="break">
<b>And</b> this.</p>
適切な出力フォーマットを作成するためのポストプロダクションも役立ちます。実際には、アルゴリズムを微調整するのに役立つので、それを行う価値があると思います(完全なデモ-見ただけで、空白の正規化はおそらくそこには適用されないため、注意して使用してください)。