2008-11-30 26 views
2

更新: 谢谢大家的意见。一些额外的信息。需要一个正则表达式来将css类添加到第一个和最后一个列表项

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

我也有能力破解脚本(电子商务之一)插入类作为导航建立。我想要限制我使用的黑客数量,以便在更新到最新版本的软件时让事情更轻松。

就这样说,我很了解我的情况和各种可供选择的选项。我的正则表达式的第一部分按预期工作。我真的或多或少地看到有人会说,“嘿哑,这很容易,只是改变这个......”

在我的努力几近结束后,这是更多的原则在这点。只知道(并学习)这个问题的解决方案。我也讨厌被一段代码殴打。

ORIGINAL:

我试图利用正则表达式类添加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); 

任何帮助将不胜感激。

+0

如果您希望能够使用任何HTML代码执行此操作,正则表达式不是一个合适的解决方案。如果你想用特定的HTML做这件事,你应该发布它,所以我们有一个样本来测试你的正则表达式。 – 2008-12-01 07:47:10

回答

3

Jamie Zawinski将有something to say about this ...

你有一个适当的HTML解析器?我不知道是否有像hpricot这样的PHP可用,但这是处理它的正确方法。你至少可以雇用hpricot为你做第一次清理。

如果您实际上正在生成HTML - 请在此处执行此操作。它看起来像你想要生成一些导航,并有一个.first.last类的东西。退一步尝试一下。

+0

感谢您的输入。 是的,我确实有一个HTML分析器可供使用。从各种来源阅读的立场是“从不用正则表达式解析HTML”,我有点期待被指向这个方向。我只是很高兴每个人的建议都做得有品位,而不是燃烧我;-) 更多的信息在组织。帖子。 – greaterweb 2008-12-01 02:12:05

1

您写道:

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

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

第二种模式:
使用。*和s一起是“危险的”,因为您可能选择整个文档直到页面的最后一页/ ul ...
和好,我只想跌落s修正及用途:(<li\s)(.*?</li>\s*</ul>)替换为:虽然我厌倦了看到杰米Zawinski撰写的<ul.*?>\s*<li

'$1class="last" $2'

鉴于上述言论的,我会写第一表达每当有一个正则表达式问题时,Dustin正确地指出你一个HTML解析器(或者从一开始就生成正确的HTML):正则表达式和HTML混合不好,因为HTML语法很复杂,除非你按照众所周知的机器生成的输出进行操作,结果非常可预测,在某些情况下,您很容易出现问题。

2

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

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

这用了jQuery可以很容易...

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

); 

正如我说的,可能会或可能不会在这种情况下,任何使用,但我认为在某些情况下,这个问题的一个有效的解决方案。 PS:你说的是有序列表,然后在你的例子中给出ul。 ol =有序列表,ul =无序列表

0

您可以将对象加载到SimpleXML对象中并使用该对象。这可以防止你打破你的标记与一些疯狂的正则表达式:)

1

我不知道是否有人关心任何更长的时间,但我有一个解决方案,在我的简单测试用例(我相信它应该在一般工作案件)。

首先,让我指出两件事:虽然PhiLho是正确的,因为点可能匹配到文档最后的所有内容,这可能就是你想要的。它只会成为一个问题,没有形成良好的网页。在大型的手动编写的页面上注意任何这样的正则表达式。

其次,php具有反斜杠的特殊含义,即使在单引号中。大多数正则表达式无论哪种方式都会表现出色,但为了以防万一,您应该始终双重摆脱它们。

现在,这里是我的代码:

<?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内输出

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

这不承担任何换行符... >标签。如果有的话,也可以在第一个表达式上使用修饰符。

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

当然,如果有机会,列表项目已经具有类别属性集合,则整个事情将不得不被扩展。另外,如果只有一个列表项目,它将匹配两次,给它两个这样的属性。至少对于xhtml来说,这会破坏验证。

0

作为前言,这是在大多数使用情况下waaay过度复杂的事情。请参阅其他答案,以更健康:)

这是我写的一个小小的PHP类来解决类似的问题。它增加了'第一','最后'和任何其他你想要的类。它将处理没有“class”属性的li以及那些已经有一些class的属性。

<?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); 
    } 
} 
相关问题