繁体   English   中英

需要一个正则表达式将CSS类添加到第一个和最后一个列表项

[英]Need a regex to add css class to first and last list item

更新:谢谢大家的投入。 一些其他信息。

实际上,这只是我正在使用的一小部分标记(20行),旨在利用正则表达式来完成这项工作。

我也确实有能力破解脚本(一个电子商务的脚本)以在构建导航时插入类。 我想限制现有的黑客数量,以便在我更新到最新版本的软件时使自己更轻松。

话虽如此,我很清楚自己的处境以及可以使用的各种选择。 我的正则表达式的第一部分按预期工作。 我或多或少张贴了一些文章,看看是否有人会说:“嘿,假人,这很容易,只需更改此.....”

经过我的一些努力后,这是更多的原则。 仅知道(并学习)此问题的解决方案。 我也讨厌被一段代码殴打。

原版的:

我试图利用正则表达式将CSS类添加到有序列表中的第一个和最后一个列表项中。 我尝试了很多不同的方法,但无法获得想要的结果。

我对第一个列表项有一个正则表达式,但似乎无法为最后一个列出正确的表达式。 这是我正在使用的:

    $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); 

任何帮助将不胜感激。

杰米·扎温斯基对此有话要说 ...

您是否有合适的HTML解析器? 我不知道是否有适用于PHP的hpricot之类的东西,但这是处理它的正确方法。 您至少可以雇用hpricot为您进行第一次清理。

如果您实际上是在生成HTML,请在此处进行。 它看起来像你想生成一些导航和拥有.first.last种就可以了嘛。 退后一步尝试一下。

+1以生成正确的html作为最佳选择。

但是一种完全不同的方法,您可能会接受也可能无法接受:可以使用javascript。

这使用jquery使其变得简单...

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

);

正如我所说,在这种情况下可能有用,也可能没有用,但是我认为在某些情况下它是解决该问题的有效方法。

PS:您说出有序列表,然后在示例中给出ul。 ol =有序列表,ul =无序列表

你写了:

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

第一种模式:
ul+ =>您搜索类似ullll ...
m修饰符在这里是无用的,因为您不使用^或$。

第二种模式:
与s一起使用。*是“危险的”,因为您可能会选择整个文档,直到页面的最后/ ul。
而且,我只需要删除s修饰符,然后使用: (<li\\s)(.*?</li>\\s*</ul>)和replace: '$1class="last" $2'

鉴于以上言论,我将写第一个表达式: <ul.*?>\\s*<li

尽管我每次看到正则表达式问题时都会厌倦看到Jamie Zawinski的报价,但Dustin正确地将您指向HTML解析器(或者只是从头开始生成正确的HTML!):正则表达式和HTML不能很好地融合在一起,因为HTML语法很复杂,并且除非您对众所周知的机器生成的输出进行操作且结果非常可预测,否则在某些情况下您很容易出错。

我不知道是否有人在乎,但是我有一个可以在我的简单测试用例中使用的解决方案(而且我相信它应该在一般情况下都可以使用)。

首先,让我指出两点:虽然PhiLho是正确的,因为s是“危险的”,但由于点可能与文档的最后部分匹配,因此这很可能就是您想要的。 只有格式不正确的页面才成为问题。 在手动编写的大页面上使用此类正则表达式时要格外小心。

其次,即使在单引号中,php也具有反斜杠的特殊含义。 大多数regexen都会以任何一种方式表现良好,但是为了以防万一,您应该始终对其进行两次转义。

现在,这是我的代码:

<?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;
?>

这将输出

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

假定开始<ul ...>标签内没有换行。 如果有的话,也可以在一个表达式上使用s修饰符。

魔术发生在(.(?<!<li))*? 这将匹配不是字符串<li开头的任何字符(点),并以非贪婪的方式(?)重复任意次数(*)。

当然,如果列表项已经设置了class属性,则必须扩展整个内容。 同样,如果只有一个列表项,它将匹配两次,并赋予它两个这样的属性。 至少对于xhtml,这会中断验证。

您可以将导航加载到SimpleXML对象中并进行处理。 这可以防止您用一些疯狂的正则表达式破坏标记:)

作为序言..在大多数用例中,这会使事情变得过于复杂。 请查看其他答案以获得更多理智:)

这是我写的一个PHP类,用于解决类似的问题。 它添加了“第一”,“最后”和您想要的任何其他类。 它将处理没有“ class”属性的li's以及已经具有某些class的li's。

<?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);
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM