PHP ile etiketleri dengelemek için nasıl

5 Cevap

Aşağıdaki dize, ben, bazı metin ile <!--more--> olarak değiştirin FOOBAR, ardından dize kesecek istiyorum.

<p>The quick <a href="/">brown</a> fox jumps <!--more-->
over the <a href="/">lazy</a> dog.</p>

Ben bu noktaya var:

<p>The quick <a href="/">brown</a> fox jumps FOOBAR

Gördüğünüz gibi ... ama, <p> etiketi kapalı değil. Herhangi Ben sürekli etiketleri denge olabilir nasıl fikir? Ben PHP için oldukça yeni.

Bu gibi görünüyor ile çalışıyorum dizisi:

array(2) {
  [0]=>
  string(50) "<p>The quick <a href="/">brown</a> fox jumps "
  [1]=>
  string(45) " over the <a href="/">lazy</a> dog.</p>"
}

5 Cevap

Ben henüz tam bu test değil, ama en azından örnek için çalışıyor. Iyi biçimli XML varsayar.

<?php
$reader = new XMLReader;
$writer = new XMLWriter;

// load the XML string into the XMLReader
$reader->xml('<p>The quick <a href="/">brown</a> fox jumps <!--more--> over the <a href="/">lazy</a> dog.</p>');
// write the new XML to memory
$writer->openMemory();
$done = false;

// XMLReader::read() moves the current read location to the next node
while ( !$done && $reader->read()) {
    // choose action based on the node type
    switch ($reader->nodeType) {
        case XMLReader::ELEMENT:
            // read an element, so write it back to the output
            $writer->startElement($reader->name);
            if ($reader->hasAttributes) {
                // loop through all attributes and write them
                while($reader->moveToNextAttribute()) {
                    $writer->writeAttribute($reader->name, $reader->value);
                }
                // move back to the beginning of the element
                $reader->moveToElement();
            }
            // if the tag is empty, close it now
            if ($reader->isEmptyElement) {
                $writer->endElement();
            }
            break;
        case XMLReader::END_ELEMENT:
            $writer->endElement();
            break;
        case XMLReader::TEXT:
            $writer->text($reader->value);
            break;
        case XMLReader::COMMENT:
            // you  can change this to be more flexible if you need
            // e.g. preg_match, trim, etc.
            if (trim($reader->value) == 'more') {

                // write whatever you want in here. If you have xml text
                // you want to write verbatim, use writeRaw() instead of text()
                $writer->text('FOOBAR');

                // this is where the magic happens -- endDocument closes
                // any remaining open tags
                $writer->endDocument();
                // stop the loop (could use "break 2", but that gets confusing
                $done = true;
            }
            break;
    }
}
echo $writer->outputMemory();

Sen wordpress force_balance_tags işlevini kullanabilirsiniz. Uygulama burada yaşıyor: -

http://core.trac.wordpress.org/browser/trunk/wp-includes/formatting.php

Bu, sadece kodu + kopyalayıp yapıştırmak bağımsız bir işlevdir.

function force_balance_tags( $text ) {

Kullanımı çok basittir

$bad_text = "<div> <p> some text </p> " ;

echo force_balance_tags ($ bad_text);

Bu wordpress parçası olduğundan, bu denenmiş ve test edilmiş ve anlık regex macthing çözümleri daha iyidir.

Mümkünse, ben (o metin düğümü kesiliyor ve ondan sonra başka child düğümleri silme, bir DOM'ye HTML ayrıştırma ve onunla bu şekilde ilgilenen, bu dizeyi bulana kadar metin düğümleri yürürken öneririm ) bozulmamış üst bırakarak. Sonra HTML DOM re-serialize.

Eğer sorununuz devlet olarak, bu kadar kolay:

str_replace('<!--more-->', 'FOOBAR', $original_text);

Belki bütün sorunu ile yapmak için bir dizi var ne anlatmaya sorunuzu güncelleme eğer doğru soruyu yorumlarken yardımcı olacak - (dize <!--more--> dizide olması gerekiyordu?)

You would have to find all tags opened, but not closed, before the placeholder text. Insert the new text like you do now, and then close the tags afterwards.

İşte özensiz bir örnektir. Ben bu kodu tüm geçerli HTML ile çalışacağını düşünüyorum, ama olumlu değilim. Ve kesinlikle geçersiz biçimlendirme kabul edecektir. ama yine de:

$h = '<p>The quick <a href="/">brown</a> fox jumps <!--more-->
over the <a href="/">lazy</a> dog.</p>';

$parts = explode("<!--more-->", $h, 2);
$front = $parts[0];

/* Find all opened tags in the front string */
$tags = array();
preg_match_all("|<([a-z][\w]*)(?: +\w*=\"[\\w/%&=]+\")*>|i", $front, $tags, PREG_OFFSET_CAPTURE);
array_shift($tags); /* get rid of the complete match from preg_match_all */

/* Check if the opened arrays have been closed in the front string */
$unclosed = array();
foreach($tags as $t) {
    list($tag, $pos) = $t[0];
    if(strpos($front, "</".$tag, $pos) == false) {
    	$unclosed[] = $tag;
    }
}    

/* Print the start, the replacement, and then close any open tags. */
echo $front;
echo "FOOBAR";
foreach($unclosed as $tag) {
    echo "</".$tag.">";
}

Çıkışlar

<p>The quick <a href="/">brown</a> fox jumps FOOBAR</p>