Найти все блоки текста между символами и запомнить их индексы
Всем привет.
Возникла у меня такая задача, необходимо найти в строке текста, все отрезки текста которые находятся между символами [color=ЦВЕТ]текст текст текст[/color], запомнить индекс начала текста (без блока [color=ЦВЕТ]!) между этими символами и индекс конца, записать значение с цветом которое стоит после color= и удалить из текста этот блок оставив лишь текст между ним. Суть примерно такая Изначальный текст Оооочень большая строка текста, [color=красный]выделенный текст[/color], еще всякий текст текст текст [color=зелёный]еще выделенный текст[/color]! Ну и тд. Надо что бы эта строка превратилась в Оооочень большая строка текста, выделенный текст, еще всякий текст текст текст еще выделенный текст! Ну и тд. и после ее обработки на выходе получался примерно вот такой массив с информацией // для каждого блока создаётся объект с данными его позиционирования и цвета // тут хранится позиция начала текста БЕЗ блока [color] и позиция окончания var array_action = [ {index_start_action: 31, index_end_action: 47, color: "красный"}, // индексы с отрезком текста - выделенный текст {index_start_action: 78, index_end_action: 98, color: "зелёный"} // индексы с отрезком текста - еще выделенный текст ] И еще момент, нужен только чистый JS, никаких плагинов библиотек и тд! Пожалуйста помогите с решением! Сам уже кучу времени убил, но ничего толкового пока что не получилось... |
function createActionForText (text) { var text_left_border_start = text.indexOf("[color="), text_left_border_end = text.indexOf("]", text_left_border_start), color = text.slice(text_left_border_start + 7, text_left_border_end), text_right_border_start = text.indexOf("[/color"), text_right_border_end = text.indexOf("]", text_right_border_start), value = text.slice(text_left_border_end + 1, text_right_border_start), text_array = text.split(""); text_array.splice(text_right_border_start, 8); text_array.splice(text_left_border_start, color.length + 8); return { text: text_array.join(""), start: text_left_border_end - (color.length + 8), end: (text_left_border_end - (color.length + 8)) + value.length, color: color } } console.log(createActionForText(text)); У меня вроде получилось примерно то что надо, но как то уж больно громоздко выглядит, может можно как то поизящнее это сделать? |
var rx = /\[color=([^\]]+)\](.*?)(?:\[\/color\]|$)/g; var array_action = []; var totalRemove = 0; var resultStr = str.replace(rx, function(a, color, txt, idx) { array_action.push({ index_start_action: idx - totalRemove, index_end_action: idx + txt.length - totalRemove }); totalRemove += color.length + 16; return txt; }); |
Alexandroppolus, Это уже намного лучше! Спасибо большое! :)
|
Arhitector,
<script> var str = 'Оооочень большая строка текста, [color=красный]выделенный текст[/color], еще всякий текст текст текст [color=зелёный]еще выделенный текст[/color]! Ну и тд.', reg = /\[([^=]+)=([^\]]+)\]([\S\s]*?)\[\/\1\]/mig, array_action = [], n = 1; str = str.replace(reg, function(a,b,c,d,e) { var index_start_action = e - n; var index_end_action = index_start_action + d.length var color = c; var obj = {index_start_action : index_start_action, index_end_action : index_end_action, color : color}; array_action.push(obj); n += a.length - d.length; return d }); document.write(str + "<br>" + JSON.stringify(array_action, null, 4)) </script> |
Вообще такие вещи делаются конечным автоматом, но по-быстрому можно и регуляркой нафигачить, как и все ребята выше:)
(версия игнорирующая незакрытые тэги и работающая со вложенностью): var str = 'Оооочень большая строка текста, [color=красный]выделенный текст[/color], еще всякий текст текст текст [color=зелёный]еще выделенный текст[/color]! Ну и тд.'; var array_action = []; var shift = 0; var start = []; var result = str.replace(/\[(\/?)color(?:\s*=\s*([^\]]+)\s*)?\]/g, function(full, end, color, index){ if(end){ if(end = start.pop()){ end.index_end_action = index - shift; array_action.push(end); } } else { start.push({ index_start_action: index - shift, color: color }) } shift += full.length; return ''; }); console.log(result, array_action); |
Вариант с String.prototype.match
<!doctype html> <html> <head><style>body { font: 120% sans-serif; }</style></head> <body> <script> // функция, выдающая строку и объект с данными о позиции цветного текста function parse(string) { var match; var spans = [], index = 0, text = [], length; while(match = string.match(/(\[color=([^\]]+)\])(.*?)(\[\/color\])/s)) { index += match.index; text.push(string.slice(0, match.index) + match[3]); length = match[0].length - match[1].length - match[4].length; spans.push({ start: index, end: index + length, color: match[2] }); index += length; string = string.slice(match.index + match[0].length); } text.push(string); return { text: text.join(""), spans }; } // пример, проверка function stringify({ text, spans }) { return spans.reduce((string, { start, end, color }, index, data) => { string.push( `<mark style="color: ${color};">${text.slice(start, end)}</mark>` ); string.push( (index + 1) in data ? text.slice(end, data[index + 1].start) : text.slice(end) ); return string; }, [text.slice(0, 0 in spans ? spans[0].start : Infinity)]).join(""); } var r = parse("Оооочень большая строка текста, [color=red]выделенный текст[/color], еще всякий текст текст текст [color=green]еще выделенный текст[/color]! Ну и тд."); document.body.innerHTML = `<pre>${JSON.stringify(r, null, "\t")}</pre>` + stringify(r); </script> </body> </html> |
Цитата:
возможно, для строки "111[color=green]222[color=red]333[/color]444[/color]555"должно быть 3 непересекающихся экшена - green для "222", red для "333", green для "444". Но и там в принципе твой вариант со стеком можно приспособить |
Часовой пояс GMT +3, время: 20:24. |