Ну, может быть, есть лучший способ, но не в моей голове (при условии, что теги не появятся в середине слов, 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 - Это самая простая часть, просто объединить измененную часть и два других бита вместе.
Я мог бы ужасно усложнить этот ум, если это так, просто игнорируй меня.