Ilk ve son liste öğesine css sınıf eklemek için bir regex ihtiyacınız var

6 Cevap php

UPDATE: Thank you all for your input. Some additional information.

Gerçekten biçimlendirme sadece küçük bir parça ben çalışıyorum (20 hat) ve işi yapmak için bir regex kaldıraç amaçladık etmişti.

Ben de navigasyon yerleşik olarak sınıfları eklemek için senaryoyu kesmek yeteneği (bir e-ticaret bir) var. Ben yazılımın en son sürümüne güncellemek to gittiğinizde myself daha kolay şeyler tutmak için yerinde var kesmek sayısını sınırlamak istedim.

Bunu dedi, ben benim durum ve benim için kullanılabilir çeşitli seçenekler oldukça farkındayım. Beklendiği gibi benim regex ilk bölümü çalışır. Ben ..... "kukla hey, bu sadece bunu değiştirmek kolaydır" Birisi, derdi olmadığını görmek için gerçekten daha fazla ya da daha az yayınlanmıştır

Benim çabaları ile birkaç yaklaştıktan sonra, bu noktada ilke daha bulunuyor. Sadece biliyorum (ve öğrenmek) bir çözüm için bu problem bulunmaktadır. Ben de bir kod parçası tarafından dövüldüğünü nefret ediyorum.

ORİJİNAL:

Ben sıralı liste içindeki ilk ve son liste öğeleri için CSS bir sınıf eklemek için düzenli ifadeler kaldıraç çalışıyorum. Ben farklı şekillerde bir sürü denedim ama ben arıyorum sonuçlar üretemez.

Ben ilk liste öğesi için normal bir ifade var ama son bir doğru olanı anlamaya görünüyor olamaz. İşte ben çalışıyorum budur:

    $patterns = array('/<ul+([^<]*)<li/m', '/<([^<]*)(?<=<li)(.*)<\/ul>/s');
    $replace = array('<ul$1<li class="first"','<li class="last"$2$3</ul>');
    $navigation = preg_replace($patterns, $replace, $navigation);

Herhangi bir yardım büyük mutluluk duyacağız.

6 Cevap

Jamie Zawinski olurdu something to say about this ...

Eğer uygun bir HTML ayrıştırıcı var mı? PHP'de hpricot gibi bir şey varsa bilmiyorum, ama onunla başa çıkmak için doğru yoldur. En az hpricot sizin için ilk temizleme yapmak için istihdam olabilir.

Aslında HTML üreten iseniz - orada bunu. Bazı navigasyon oluşturmak ve bir .first ve bunun üzerine bir şey .last tür istediğiniz gibi görünüyor. Bir adım geri atın ve deneyin.

En iyi seçenek olarak doğru html üreten +1.

Ama ya sizin için kabul edilebilir olmayabilir tamamen farklı bir yaklaşım: Eğer javascript kullanabilirsiniz.

Bu kolay yapmak için jquery kullanıyor ...

$(document).ready(
    function() {
        $('#id-of-ul:firstChild').addClass('first');        
        $('#id-of-ul:lastChild').addClass('last');
    }

);

Dediğim gibi, ya da bu durumda herhangi bir kullanımı olabilir, ama ben bazı durumlarda sorun onun geçerli bir çözüm düşünmek olmayabilir.

PS: Bu sıralı liste söylemek, sonra örnekte ul vermek. ol = sıralı liste ul = Sırasız liste

You yazdı:

$patterns = array('/<ul+([^<]*)<li/m','/<([^<]*)(?<=<li)(.*)<\/ul>/s');

First pattern:
ul+ => you search something like ullll...
The m modifier is useless here, since you don't use ^ nor $.

Second pattern:
Using .* along with s is "dangerous", because you might select the whole document up to the last /ul of the page...
And well, I would just drop s modifier and use: (<li\s)(.*?</li>\s*</ul>) with replace: '$1class="last" $2'

Yukarıdaki açıklamalar ışığında, ben ilk ifadeyi yazarsınız: <ul.*?>\s*<li

Ben Jamie Zawinski bir regex soru var her zaman alıntı görme yorgun olsam da, Dustin doğru bir HTML çözümleyici sizi işaret olduğunu (ya da sadece baştan doğru HTML üretmek!): Regexes ve HTML iyice karıştırın değil, HTML sözdizimi karmaşık ve çok öngörülebilir bir sonuç ile iyi bilinen makine üretilen çıktı hareket sürece, bazı durumlarda bir şey kırılmasını almak yatkındır çünkü.

Herkes artık umurunda olmadığını ben bilmiyorum, ama ben (ve ben o genel durumda çalışmak gerektiğine inanıyoruz) benim basit bir test durumunda çalışır bir çözüm var.

İlk olarak, bana iki şeyi işaret edelim: PhiLho bu doğru iken noktalar belgenin nihai kadar, bu çok iyi istediğiniz ne olabilir her şeyi karşılayan olabilir çünkü s, "tehlikeli" dir. O sadece iyi oluşmuş değil sayfaları ile bir sorun haline gelir. Büyük, elle yazılmış sayfaları üzerinde herhangi bir tür regex dikkatli olun.

İkincisi, php hatta tek tırnak içinde, ters eğik özel bir anlamı vardır. En regexen de iki şekilde gerçekleştirir, ancak her zaman çift onları kaçmak gerekir, sadece durumda.

Şimdi, burada benim kod:

<?php
$navigation='<ul>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
<li>Beer</li>
<li>Water</li>
</ul>';

$patterns = array('/<ul.*?>\\s*<li/',
                  '/<li((.(?<!<li))*?<\\/ul>)/s');
$replace = array('$0 class="first"',
                 '<li class="last"$1');
$navigation = preg_replace($patterns, $replace, $navigation);
echo $navigation;
?>

Bu irade çıktı

<ul>
<li class="first">Coffee</li>
<li>Tea</li>
<li>Milk</li>
<li>Beer</li>
<li class="last">Water</li>
</ul>

Bu hiçbir satır açılması içinde beslemeleri varsayar tag. Herhangi bir varsa, çok birinci ifadesi üzerindeki s değiştirici kullanmak.

Sihirli (.(?<!<li))*? olur. Bu <li, olmayan açgözlü moda kez herhangi bir miktarda (*) tekrarlanan dize başlangıcı olmayan herhangi bir karakter (nokta) (?) Maç olacak.

Liste öğeleri zaten class set özniteliği bir şans varsa tabii ki, her şey genişletilmiş olması gerekir. Sadece bir liste öğesi varsa da, bu o iki tür özelliklerini vererek, iki maç olacak. En azından xhtml için, bu doğrulama kıracak.

Bir SimpleXML nesne navigasyon yüklemek ve bu işe yarayabilir. Bu, bazı çılgın regex ile biçimlendirme kırma engeller :)

Önsöz olarak .. bu waaay en kullanımı-durumda şeyler üzerinde-ağırlaştırmaktadır. Daha aklı başka cevaplarına bakınız :)

Burada benzer bir sorunu çözmek için yazdığı küçük bir PHP sınıfı. Bu 'son' ve istediğiniz diğer sınıflar, 'ilk' ekler. Bu özellik zaten yanı sıra bazı sınıf (lar) var olanlar hayır "sınıf" ile li adlı idare edecektir.

<?php
/**
 * Modify list items in pre-rendered html.
 *
 * Usage Example:
 *  $replaced_text = ListAlter::addClasses($original_html, array('cool', 'awsome'));
 */
class ListAlter {
  private $classes = array();
  private $classes_found = FALSE;
  private $count = 0;
  private $total = 0;

  // No public instances.
  private function __construct() {}

  /**
   * Adds 'first', 'last', and any extra classes you want.
   */
  static function addClasses($html, $extra_classes = array()) {
    $instance = new self();
    $instance->classes = $extra_classes;
    $total = preg_match_all('~<li([^>]*?)>~', $html, $matches);
    $instance->total = $total ? $total : 0;
    return preg_replace_callback('~<li([^>]*?)>~', array($instance, 'processListItem'), $html);
  }

  private function processListItem($matches) {
    $this->count++;
    $this->classes_found = FALSE;
    $processed = preg_replace_callback('~(\w+)="(.*?)"~', array($this, 'appendClasses'), $matches[0]);
    if (!$this->classes_found) {
      $classes = $this->classes;
      if ($this->count == 1) {
        $classes[] = 'first';
      }
      if ($this->count == $this->total) {
        $classes[] = 'last';
      }
      if (!empty($classes)) {
        $processed = rtrim($matches[0], '>') . ' class="' . implode(' ', $classes) . '">';
      }
    }
    return $processed;
  }

  private function appendClasses($matches) {
    array_shift($matches);
    list($name, $value) = $matches;
    if ($name == 'class') {
      $value = array_filter(explode(' ', $value));
      $value = array_merge($value, $this->classes);
      if ($this->count == 1) {
        $value[] = 'first';
      }
      if ($this->count == $this->total) {
        $value[] = 'last';
      }
      $value = implode(' ', $value);
      $this->classes_found = TRUE;
    }
    return sprintf('%s="%s"', $name, $value);
  }
}