Разбор вложенных структур (парсинг CSS)
Задача не совсем типичная, хочу написать небольшой анализатор кода для разбора вложенных структур, которые должны транслироваться в валидный CSS.
Однако не получается захватить идентификаторы родительских селекторов. Пример вложенной структуры: #foo { border: 1px; a { border: 2px; } b { border: 3px; c { border: 4px; /* comment */ } } } То, что я хочу получить в итоге: #foo { border: 1px; } #foo a { border: 2px; } #foo b { border: 3px; } #foo b c { border: 4px; /* comment */ } Пока что получилось добиться такого результата: c { border: 4px; /* comment */ } b { border: 3px; } a { border: 2px; } #foo { border: 1px; } Код, который выполняет разбор (на С++ правда, лень было переписывать на JS, но надеюсь будет понятно, т.к. там нужно только итератор на charAt() заменить ) :) #include <iostream> #include <iterator> #include <string> using namespace std; int main() { string str = "\ #foo {\ border: 1px;\ a {\ border: 2px;\ }\ b {\ border: 3px;\ c {\ border: 4px; /* comment */\ }\ }\ }"; string::const_iterator i = str.end(), begin = str.begin(), end; while (i != begin) { if (*i == ';' || (*i == '/' && *(i-1) == '*')) { end = i++; while (*i-- != '{'); while (true) { if (*i == ';' || *i == '}' || *i == '{' || i == begin) break; i--; } string item(++i, ++end); cout << item << "}" << endl; } i--; } return 0; } Возможно я не так начал разбор, но идея была такая: сперва получить идентификаторы, которых мне не хватает, а затем объеденить с тем что есть. Осталось собрать имена селекторов. Иными словами мне нужно получить массив с такими селекторами: ['#foo', '#foo a', '#foo b', '#foo b c'] Если есть какие-то идеи по поводу алгоритма с удовольствием выслушаю. |
мне кажется такие вещи надо писать как автомат, контролируя логику парсера матрицей переходов, а не хардкорить ее
|
В идеале да, так оно и будет (пример грамматики).
Сейчас же мне просто нужно понять сам алгоритм получения родительских селекторов для каждого блока, с какой стороны подобраться. |
Ну есть тупой вариант, - рекурсивный реплейс снизу.
Т.е. регой типа /([^{\s]+)\s*\{([^}]+)\}/g, рекурсивно пройтись, заменяя на идентификаторы, а потом обратно - идентификаторы на дополненные значения. А вот как умно и красиво - навскидку не скажешь.) |
Не регой такие дела не далают. Согласно правилам синтаксического анализа считывать нужно посимвольно запоминая уровни. Вот только как это грамотно сделать большой вопрос.
|
Ну нязнанаю, парсинг обычно регой и делают.)
Посимвольно это вообще заумь будет, а на счёт скорости не ясно. С другой стороны если не лень уйти в далёкие дали, то наверное можно. |
Цитата:
Может по тому что в С никогда не было регекстов, а в С++ они появились только в сентябре прошлого года (шутка) Цитата:
|
Максимально тупо. Сейчас набросаю.)
|
Сделано на коленке, не красиво, не оптимизировано, но суть отображает.
<div> #foo { border: 1px; a { border: 2px; } b { border: 3px; c { border: 4px; /* comment */ } } } </div> <script> d=document.getElementsByTagName('div')[0].innerHTML; function css(str){ var result=[], re = /([^{\s]+)\s*\{[^}{]+\}/g, re2 = /(\d+)_array/g, placer = function( all , selector){ var lower=''; all = all.replace( re2 ,function(x,y){ result[y] = selector + ' ' + result[y]; lower += x; return '' }) return result.push( all + '\n') - 1 + '_array' + lower; } while(~str.indexOf('{'))alert( str=str.replace( re , placer ) ); return str.replace( re2 , function(ar,ar){ return result[ar] } ) } alert(css(d)) </script> |
Хм... понял, подумаю как без регексов переписать)
|
Часовой пояс GMT +3, время: 12:40. |