복붙노트

preg_replace에서 html 태그를 무시하십시오.

PHP

preg_replace에서 html 태그를 무시하십시오.

이 preg_replace에서 html 태그를 무시하려면 어떻게해야합니까? 검색을 위해 foreach 함수가 있으므로 누군가가 "apple span"을 검색하면 preg_replace도 span 및 html break에 범위를 적용합니다.

preg_replace("/($keyword)/i","<span class=\"search_hightlight\">$1</span>",$str);

미리 감사드립니다!

해결법

  1. ==============================

    1.정규식을 사용하는 대신 DOMDocument 및 DOMXPath를 기반으로 함수를 작성해야한다고 가정합니다. 그것들이 꽤 강력하더라도 정규 표현식으로 해결하기가 쉽지는 않지만 항상 (항상) 쉽게 설명 할 수있는 문제와 마주하게됩니다.

    정규식을 사용하는 대신 DOMDocument 및 DOMXPath를 기반으로 함수를 작성해야한다고 가정합니다. 그것들이 꽤 강력하더라도 정규 표현식으로 해결하기가 쉽지는 않지만 항상 (항상) 쉽게 설명 할 수있는 문제와 마주하게됩니다.

    일반적인 말은 : HTML을 정규 표현식으로 구문 분석하지 마십시오.

    모든 규칙과 마찬가지로 항상 명심해야 할 좋은 규칙이며, 항상 적용되는 것은 아니며, 그것에 대해 마음을 굳힐 가치가 있습니다.

    XPath를 사용하면 모든 XML 요소를 무시하고 텍스트 내에서만 검색어가 포함 된 모든 텍스트를 찾을 수 있습니다.

    그런 다음 해당 텍스트를 으로 감싸기 만하면됩니다.

    편집 : 마침내 일부 코드;)

    먼저 xpath를 사용하여 검색 텍스트가 포함 된 요소를 찾습니다. 내 쿼리는 다음과 같을 것입니다.이 쿼리는 더 잘 작성 될 수 있습니다. 저는 프로가 아닌 xpath 프로입니다.

    '//*[contains(., "'.$search.'")]/*[FALSE = contains(., "'.$search.'")]/..'
    

    $ search는 검색 할 텍스트를 포함하고 "(따옴표) 문자를 포함하지 않습니다 (이 경우 괄호 안에 들어 있습니다. 따옴표가 필요할 경우 xpath 속성 정리 및 sanitizing을 참조하십시오).

    이 쿼리는 함께 넣어지는 textnodes를 포함하는 모든 부모를 검색 용어가 포함 된 문자열로 반환합니다.

    그러한 목록은 그대로 처리하기가 쉽지 않기 때문에 DOMText 노드 목록을 나타내는 TextRange 클래스를 만들었습니다. textnodes리스트가 하나의 문자열 인 것처럼 문자열 연산을 수행하는 것이 유용합니다.

    이것은 루틴의 기본 골격입니다.

    $str = '...'; # some XML
    
    $search = 'text that span';
    
    printf("Searching for: (%d) '%s'\n", strlen($search), $search);
    
    $doc = new DOMDocument;
    $doc->loadXML($str);
    $xp = new DOMXPath($doc);
    
    $anchor = $doc->getElementsByTagName('body')->item(0);
    if (!$anchor)
    {
        throw new Exception('Anchor element not found.');
    }
    
    // search elements that contain the search-text
    $r = $xp->query('//*[contains(., "'.$search.'")]/*[FALSE = contains(., "'.$search.'")]/..', $anchor);
    if (!$r)
    {
        throw new Exception('XPath failed.');
    }
    
    // process search results
    foreach($r as $i => $node)
    {   
        $textNodes = $xp->query('.//child::text()', $node);
    
        // extract $search textnode ranges, create fitting nodes if necessary
        $range = new TextRange($textNodes);        
        $ranges = array();
        while(FALSE !== $start = strpos($range, $search))
        {
            $base = $range->split($start);
            $range = $base->split(strlen($search));
            $ranges[] = $base;
        };
    
        // wrap every each matching textnode
        foreach($ranges as $range)
        {
            foreach($range->getNodes() as $node)
            {
                $span = $doc->createElement('span');
                $span->setAttribute('class', 'search_hightlight');
                $node = $node->parentNode->replaceChild($span, $node);
                $span->appendChild($node);
            }
        }
    }
    

    내 예제 XML :

    <html>
        <body>
            This is some <span>text</span> that span across a page to search in.
        and more text that span</body>
    </html>
    

    다음 결과가 생성됩니다.

    <html>
        <body>
            This is some <span><span class="search_hightlight">text</span></span><span class="search_hightlight"> that span</span> across a page to search in.
        and more <span class="search_hightlight">text that span</span></body>
    </html>
    

    이는 심지어 여러 태그에 분산 된 텍스트를 찾을 수 있음을 보여줍니다. 그것은 정규 표현식으로는 그렇게 쉽게 가능하지 않습니다.

    여기서 전체 코드를 찾으십시오 : http://codepad.viper-7.com/U4bxbe (Answer 예제에서 가져온 TextRange 클래스 포함).

    사이트가 사용하고있는 오래된 LIBXML 버전 때문에 바이퍼 코드 패드에서 제대로 작동하지 않습니다. 그것은 내 LIBXML 버전 20707 잘 작동합니다.이 문제에 대한 관련 질문을 만들었습니다 : XPath 쿼리 결과 순서.

    주의 사항 :이 예제에서는 바이너리 문자열 검색 (strpos)과 DOMText :: splitText 함수로 텍스트 노드를 분할하는 데 관련된 오프셋을 사용합니다. 함수가 UTF-8 문자 오프셋을 필요로하므로 잘못된 오프셋이 발생할 수 있습니다. 올바른 방법은 mb_strpos를 사용하여 UTF-8 기반 값을 얻는 것입니다.

    이 예제는 예제 데이터에 대해 UTF-8과 동일한 오프셋을 갖는 US-ASCII 만 사용하기 때문에 어쨌든 작동합니다.

    실생활의 경우, $ 검색 문자열은 UTF-8로 인코딩되어야하며 mb_strpos가 strpos 대신 사용되어야합니다.

     while(FALSE !== $start = mb_strpos($range, $search, 0, 'UTF-8'))
    
  2. from https://stackoverflow.com/questions/8193327/ignore-html-tags-in-preg-replace by cc-by-sa and MIT license