сохраните HTMLformat после замены некоторый текст (использующий PHP и JS)

Я хотел бы, изменяют HTML как

I am <b>Sadi, novice</b> programmer.

кому:

I am <b>Sadi, learner</b> programmer.

Чтобы сделать это, я буду искать использование строки "программист новичка". Как я могу сделать это? Какая-либо идея?

Это ищет использование больше чем одного слова "программист новичка". Это могло быть целое предложение. Дополнительный пробел (например, новая строка, вкладка) должен быть проигнорирован, и любой тег должен быть проигнорирован во время поиска. Но во время замены должен быть сохранен тег.

Это - своего рода преобразователь. Будет лучше, если это будет нечувствительно к регистру.

Спасибо

Sadi


Больше разъяснения:

Я получаю некоторый хороший ответ с возможным решением. Но продолжайте отправлять при учитывании какой-либо идеи в виду.

Я хотел бы больше разъяснить проблему на всякий случай, любой пропустил ее. Основное сообщение показывает проблему сценарием в качестве примера.

1) Теперь проблема, находят и заменяют некоторую строку, не рассматривая тегов. Теги могут обнаруживаться в отдельном слове. Строка может содержать несколько слово. Тег только появляется в довольном строка или документ. Поисковая фраза никогда не содержит тегов.

Мы можем легко удалить все теги и сделать некоторую текстовую операцию. Но здесь другая проблема обнаруживается.

2) Теги должны быть прерогативой, даже после замены текста. Именно это показывает пример.

Еще раз спасибо за помощь

15
задан Sadi 16 April 2010 в 02:54
поделиться

6 ответов

хорошо, я думаю, это то, что вы хотите. он выполняет поиск и замену вашего ввода, разбивает их на массивы строк, разделенных пробелом, генерирует регулярное выражение, которое находит входное предложение с любым количеством тегов пробелов / html и заменяет его предложением замены с теми же тегами, замененными между словами .

если количество слов в поисковом предложении больше, чем в замещающем, оно просто использует пробелы между любыми дополнительными словами, а если количество слов для замены больше, чем в поисковом, в конце будут добавлены все «потерянные» теги. он также обрабатывает символы регулярного выражения при поиске и замене.

<?php
function htmlFriendlySearchAndReplace($find, $replace, $subject) {
    $findWords = explode(" ", $find);
    $replaceWords = explode(" ", $replace);

    $findRegexp = "/";
    for ($i = 0; $i < count($findWords); $i++) {
        $findRegexp .= preg_replace("/([\\$\\^\\|\\.\\+\\*\\?\\(\\)\\[\\]\\{\\}\\\\\\-])/", "\\\\$1", $findWords[$i]);
        if ($i < count($findWords) - 1) {
            $findRegexp .= "(\s?(?:<[^>]*>)?\s(?:<[^>]*>)?)";
        }
    }
    $findRegexp .= "/i";

    $replaceRegexp = "";
    for ($i = 0; $i < count($findWords) || $i < count($replaceWords); $i++) {
        if ($i < count($replaceWords)) {
            $replaceRegexp .= str_replace("$", "\\$", $replaceWords[$i]);
        }
        if ($i < count($findWords) - 1) {
            $replaceRegexp .= "$" . ($i + 1);
        } else {
            if ($i < count($replaceWords) - 1) {
                $replaceRegexp .= " ";
            }
        }
    }

    return preg_replace($findRegexp, $replaceRegexp, $subject);
}
?>

Вот результаты нескольких тестов:

Original : <b>Novice Programmer</b>
Search : Novice Programmer
Replace : Advanced Programmer
Result : <b>Advanced Programmer</b>

Original : Hi, <b>Novice Programmer</b>
Search : Novice Programmer
Replace : Advanced Programmer
Result : Hi, <b>Advanced Programmer</b>

Original : I am not a <b>Novice</b> Programmer
Search : Novice Programmer
Replace : Advanced Programmer
Result : I am not a <b>Advanced</b> Programmer

Original : Novice <b>Programmer</b> in the house
Search : Novice Programmer
Replace : Advanced Programmer
Result : Advanced <b>Programmer</b> in the house

Original : <i>I am not a <b>Novice</b> Programmer</i>
Search : Novice Programmer
Replace : Advanced Programmer
Result : <i>I am not a <b>Advanced</b> Programmer</i>

Original : I am not a <b><i>Novice</i> Programmer</b> any more
Search : Novice Programmer
Replace : Advanced Programmer
Result : I am not a <b><i>Advanced</i> Programmer</b> any more

Original : I am not a <b><i>Novice</i></b> Programmer any more
Search : Novice Programmer
Replace : Advanced Programmer
Result : I am not a <b><i>Advanced</i></b> Programmer any more

Original : I am not a Novice<b> <i> </i></b> Programmer any more
Search : Novice Programmer
Replace : Advanced Programmer
Result : I am not a Advanced<b> <i> </i></b> Programmer any more

Original : I am not a Novice <b><i> </i></b> Programmer any more
Search : Novice Programmer
Replace : Advanced Programmer
Result : I am not a Advanced <b><i> </i></b> Programmer any more

Original : <i>I am a <b>Novice</b> Programmer</i> too, now
Search : Novice Programmer too
Replace : Advanced Programmer
Result : <i>I am a <b>Advanced</b> Programmer</i> , now

Original : <i>I am a <b>Novice</b> Programmer</i>, now
Search : Novice Programmer
Replace : Advanced Programmer Too
Result : <i>I am a <b>Advanced</b> Programmer Too</i>, now

Original : <i>I make <b>No money</b>, now</i>
Search : No money
Replace : Mucho$1 Dollar$
Result : <i>I make <b>Mucho$1 Dollar$</b>, now</i>

Original : <i>I like regexp, you can do [A-Z]</i>
Search : [A-Z]
Replace : [Z-A]
Result : <i>I like regexp, you can do [Z-A]</i>
4
ответ дан 1 December 2019 в 05:07
поделиться

Что ж, может быть, есть способ получше, но не в порядке (если предположить, что теги не будут появляться в середине слов, HTML - это правильно сформированный и т. д.) ...

По сути, вам понадобятся три вещи (извините, если это звучит снисходительно, не предназначено для этого): 1. Метод сопоставления подстрок, игнорирующий теги. 2. Способ сделать замену с сохранением тегов. 3. Способ собрать все воедино.

1 - Это, наверное, самый сложный момент. Одним из методов было бы перебрать все символы в исходной строке (строки в основном представляют собой массивы символов, поэтому вы можете получить доступ к символам, как если бы они были элементами массива), пытаясь сопоставить как можно больше символов из строки поиска, останавливая когда вы либо сопоставили все символы, либо закончились символы для сопоставления. Любые символы между «<» и «>» включительно следует игнорировать. Какой-то псевдокод (проверьте это, он поздно и могут быть ошибки):

findMatch(startingPos : integer, subject : string, searchString : string){
    //Variables for keeping track of characters matched, positions, etc.
    inTag = false;
    matchFound = false;
    matchedCharacters = 0;
    matchStart = 0;
    matchEnd = 0;

    for(i from startingPos to length(searchString)){
        //Work out when entering or exiting tags, ignore tag contents
        if(subject[i] == '<' || subject[i] == '>'){
            inTag = !inTag;
        }
        else if(!inTag){
            //Check if the character matches expected in search string
            if(subject[i] == searchString[matchedCharacters]){
                if(!matchFound){
                    matchFound = true;
                    matchStart = i;
                }
                matchedCharacters++;

                //If all of the characters have been matched, return the start and end positions of the substring
                if(matchedCharacters + 1 == length(searchString)){
                    matchEnd = i - matchStart;
                    return matchStart, matchEnd;
                }
            }
            else{
                //Reset counts if not found
                matchFound = false;
                matchCharacters = 0;
            }
        }
    }
    //If no full matches were found, return error
    return -1;
}

2 - Разделите исходный код HTML на три строки - бит, над которым вы хотите работать (между двумя позициями, возвращаемыми функцией сопоставления) и часть до и после. Разделите бит, который вы хотите изменить, например:

$parts = preg_split("/(<[^>]*>)/",$string, -1, PREG_SPLIT_DELIM_CAPTURE);

Сохраните запись о том, где находятся теги, объедините сегменты без тегов и выполните замену подстроки на них как обычно, затем снова разделите измененную строку и соберите заново с теги на месте.

3 - Это простая часть, просто соедините измененную часть и два других бита обратно вместе.

Я мог ужасно усложнить этот ум, если так, просто игнорируй меня.

1
ответ дан 1 December 2019 в 05:07
поделиться

Я бы сделал следующее:

if (preg_match('/(.*)novice((?:<.*>)?\s(?:<.*>)?programmer.*)/',$inString,$attributes) {
  $inString = $attributes[1].'learner'.$attributes[2];
}

Он должен соответствовать любому из следующего:

novice programmer
novice</b> programmer
novice </b>programmer
novice<span> programmer

Тестовая версия того, что утверждает регулярное выражение, будет выглядеть примерно так: Сопоставьте любой набор символов, пока вы не дойдете до «новичка», и поместите его в группа захвата, тогда, возможно, сопоставьте что-то, что начинается с '<' и имеет любое количество символов после него, а затем заканчивается '>' (но не захватывает его), но тогда будет совпадать только что-то с пробелом и затем, возможно, снова сопоставьте что-то, что начинается с '<' и имеет любое количество символов после него, а затем заканчивается '>' (но не фиксирует его), за которым затем должен следовать программист, за которым следует любое количество символов и поставить что в группу захвата.

Я бы сделал некоторые специальные тесты, так как я мог кое-что пропустить. Regex - лучший друг программистов!

3
ответ дан 1 December 2019 в 05:07
поделиться

Если он еще не написан командой COM, регулярное выражение было бы лучшим вариантом:

$cleaned_string = preg_replace('/\<.\>/', $raw_text, "");

Или что-то в этом роде. Мне нужно будет исследовать / протестировать регулярное выражение.

Затем вы можете просто использовать простой $ foobar = str_replace ($ find, $ replace_with, $ cleaned_string); , чтобы найти текст, который вы хотите заменить.

Не осознавал, что хочет вернуть HTML. Это все регулярное выражение для этого, и больше, чем я знаю на данный момент.

Зная то, что я знаю, с технической точки зрения я, вероятно, использовал бы выражение, которое не игнорировало пробелы между словами, но делало их между < и > скобки, затем используйте для вывода возможности регулярного выражения, содержащие переменные.

0
ответ дан 1 December 2019 в 05:07
поделиться

Интересная задача.

Я бы использовал DOM и XPath, чтобы найти ближайшие узлы, содержащие этот текст, а затем использовать сопоставление подстрок, чтобы узнать, какой бит строки находится в каком узле. Тем не менее, это будет включать в себя сопоставление символов и возможное обратное отслеживание.

Вот первая часть, поиск узлов-контейнеров:

<?php
error_reporting(E_ALL);
header('Content-Type: text/plain; charset=UTF-8');

$doc = new DOMDocument();
$doc->loadHTML(<<<EOD
<p>
    <span>
        <i>
            I am <b>Sadi, novice</b> programmer.
        </i>
    </span>
</p>
<ul>
    <li>
        <div>
            I am <em>Cornholio, novice</em> programmer of television shows.
        </div>
    </li>
</ul>
EOD
);
$xpath = new DOMXPath($doc);
// First, get a list of all nodes containing the text anywhere in their tree.
$nodeList = $xpath->evaluate('//*[contains(string(.), "programmer")]');
$deepestNodes = array();
// Now only keep the deepest nodes, because the XPath query will also return HTML, BODY, ...
foreach ($nodeList as $node) {
    $deepestNodes[] = $node;
    $ancestor = $node;
    while (($ancestor = $ancestor->parentNode) && ($ancestor instanceof DOMElement)) {
        $deepestNodes = array_filter($deepestNodes, function ($existingNode) use ($ancestor) {
            return ($ancestor !== $existingNode);
        });
    }
}
foreach ($deepestNodes as $node) {
    var_dump($node->tagName);
}

Надеюсь, это вам поможет.

0
ответ дан 1 December 2019 в 05:07
поделиться

Поскольку вы не дали точных сведений о том, для чего вы это будете использовать, я воспользуюсь вашим примером «Я сади, начинающий программист».

$before = 'I am <b>sadi, novice</b> programmer';
$after = preg_replace ('/I am (<.*>)?(.*), novice(<.*>)? programmer/','/I am $1$2,     learner$3 programmer/',$string);

В качестве альтернативы для любого текста:

$string = '<b>Hello</b>, world!';
$orig = 'Hello';
$replace = 'Goodbye';
$pattern = "/(<.*>)?$orig(<.*>)?/";
$final = "/$1$replace$2/";
$result = preg_replace($pattern,$final,$string);
//$result should now be 'Goodbye, world!'

Надеюсь, что это помогло. : d

Изменить: Пример вашего примера со второй частью кода: $ string = 'Я сади, начинающий программист.';
{{1 }} $ orig = 'novice';
$ replace = 'Learner';
$ pattern = "/ (<. >)? $ orig (< . >)? / ";
$ final =" $ 1 $ replace $ 2 ";
$ result = htmlspecialchars (preg_replace ($ pattern, $ final, $ строка));
echo $ result;

Единственная проблема заключается в том, что вы искали что-то, длина которого превышает одно слово.

Редактировать 2: Наконец-то придумал способ сделать это с помощью нескольких слов. Вот код:

function htmlreplace($string,$orig,$replace) 
 {
  $orig = explode(' ',$orig);
  $replace = explode(' ',$replace);
  $result = $string;
  while (count($orig)>0)
   {
    $shift = array_shift($orig);
    $rshift = array_shift($replace);

    $pattern = "/$shift\s?(<.*>)?/";
    $replacement = "$rshift$1";
    $result = preg_replace($pattern,$replacement,$result);
   }
  $result .= implode(' ',$replace);
  return $result;
 }

Удачи! : d

0
ответ дан 1 December 2019 в 05:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: