Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 29.01.2012, 15:31
Особый гость
Посмотреть профиль Найти все сообщения от monolithed
 
Регистрация: 02.04.2010
Сообщений: 4,260

Разбор вложенных структур (парсинг 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']


Если есть какие-то идеи по поводу алгоритма с удовольствием выслушаю.

Последний раз редактировалось monolithed, 29.01.2012 в 15:43.
Ответить с цитированием
  #2 (permalink)  
Старый 29.01.2012, 15:55
Аватар для Gvozd
Матрос
Отправить личное сообщение для Gvozd Посмотреть профиль Найти все сообщения от Gvozd
 
Регистрация: 04.04.2008
Сообщений: 6,246

мне кажется такие вещи надо писать как автомат, контролируя логику парсера матрицей переходов, а не хардкорить ее
Ответить с цитированием
  #3 (permalink)  
Старый 29.01.2012, 16:03
Особый гость
Посмотреть профиль Найти все сообщения от monolithed
 
Регистрация: 02.04.2010
Сообщений: 4,260

В идеале да, так оно и будет (пример грамматики).
Сейчас же мне просто нужно понять сам алгоритм получения родительских селекторов для каждого блока, с какой стороны подобраться.

Последний раз редактировалось monolithed, 29.01.2012 в 16:25.
Ответить с цитированием
  #4 (permalink)  
Старый 29.01.2012, 16:36
Аватар для Aetae
Тлен
Отправить личное сообщение для Aetae Посмотреть профиль Найти все сообщения от Aetae
 
Регистрация: 02.01.2010
Сообщений: 6,589

Ну есть тупой вариант, - рекурсивный реплейс снизу.
Т.е. регой типа /([^{\s]+)\s*\{([^}]+)\}/g, рекурсивно пройтись, заменяя на идентификаторы, а потом обратно - идентификаторы на дополненные значения.

А вот как умно и красиво - навскидку не скажешь.)
__________________
29375, 35

Последний раз редактировалось Aetae, 29.01.2012 в 16:40.
Ответить с цитированием
  #5 (permalink)  
Старый 29.01.2012, 16:48
Особый гость
Посмотреть профиль Найти все сообщения от monolithed
 
Регистрация: 02.04.2010
Сообщений: 4,260

Не регой такие дела не далают. Согласно правилам синтаксического анализа считывать нужно посимвольно запоминая уровни. Вот только как это грамотно сделать большой вопрос.
Ответить с цитированием
  #6 (permalink)  
Старый 29.01.2012, 16:52
Аватар для Aetae
Тлен
Отправить личное сообщение для Aetae Посмотреть профиль Найти все сообщения от Aetae
 
Регистрация: 02.01.2010
Сообщений: 6,589

Ну нязнанаю, парсинг обычно регой и делают.)
Посимвольно это вообще заумь будет, а на счёт скорости не ясно.
С другой стороны если не лень уйти в далёкие дали, то наверное можно.
__________________
29375, 35
Ответить с цитированием
  #7 (permalink)  
Старый 29.01.2012, 16:56
Особый гость
Посмотреть профиль Найти все сообщения от monolithed
 
Регистрация: 02.04.2010
Сообщений: 4,260

Сообщение от Aetae
Ну нязнанаю, парсинг обычно регой и делают.
Разбор email адресов и пр. да, но в формальной грамматике все посимвольно.
Может по тому что в С никогда не было регекстов, а в С++ они появились только в сентябре прошлого года (шутка)

Сообщение от Aetae
рекурсивно пройтись, заменяя на идентификаторы, а потом обратно - идентификаторы на дополненные значения.
Не совсем понял что ты имел ввиду, как сами идентификаторы получить, чтобы учесть дочерние уровни?

Последний раз редактировалось monolithed, 29.01.2012 в 17:29.
Ответить с цитированием
  #8 (permalink)  
Старый 29.01.2012, 17:21
Аватар для Aetae
Тлен
Отправить личное сообщение для Aetae Посмотреть профиль Найти все сообщения от Aetae
 
Регистрация: 02.01.2010
Сообщений: 6,589

Максимально тупо. Сейчас набросаю.)
__________________
29375, 35
Ответить с цитированием
  #9 (permalink)  
Старый 29.01.2012, 17:38
Аватар для Aetae
Тлен
Отправить личное сообщение для Aetae Посмотреть профиль Найти все сообщения от Aetae
 
Регистрация: 02.01.2010
Сообщений: 6,589

Сделано на коленке, не красиво, не оптимизировано, но суть отображает.
<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>
__________________
29375, 35

Последний раз редактировалось Aetae, 29.01.2012 в 17:40.
Ответить с цитированием
  #10 (permalink)  
Старый 29.01.2012, 17:56
Особый гость
Посмотреть профиль Найти все сообщения от monolithed
 
Регистрация: 02.04.2010
Сообщений: 4,260

Хм... понял, подумаю как без регексов переписать)
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
JQuery CSS анализатор javascript jQuery 2 15.08.2010 21:27
Подскажите по CSS меню Александр_1988 Элементы интерфейса 1 17.05.2010 11:58