Как я могу искать CSS с помощью Perl? - PullRequest
1 голос
/ 04 июня 2009

Первый вопрос от давнего пользователя.

Я пишу Perl-скрипт, который будет проходить через ряд HTML-файлов, построчно искать в них экземпляры «color:» или «background-color:» (теги CSS) и распечатывать весь линия, когда он сталкивается с одним из этих случаев. Это довольно просто.

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

Я хочу, чтобы он обнаружил экземпляр «color:» или «background-color»: я хочу, чтобы он проследил назад и нашел имя элемента, а также напечатал его. Например:

Если мой документ содержал следующий CSS:

.css_class {
    font-size: 18px;
    font-weight: bold;
    color: #FFEFA1;
        font-family: Arial, Helvetica, sans-serif;
}

Я бы хотел, чтобы скрипт выводил что-то вроде:

css_class,#FFEFA1

В идеале это будет выводить это как текстовый файл.

Буду очень признателен за любые советы, которые мне могут быть даны по этому поводу!

Вот мой сценарий в полном объеме:

$color = "color:";


open (FILE, "index.html");  
@document = `<FILE>`;  
close (FILE);  

foreach $line (@document){  
    if($line =~ /$color/){  
        print $line;  
    }  
}   

Ответы [ 5 ]

5 голосов
/ 04 июня 2009

Поскольку вы обратились за советом (а это не услуга кодирования), я предложу просто , что.

Всегда используйте ограничения и предупреждения:

use strict;
use warnings;

Всегда проверяйте возвращаемое значение open звонков:

open(FILE, 'filename') or die "Can't read file 'filename' [$!]\n";

Используйте трехглавую форму открытых и лексических файловых дескрипторов вместо глобусов:

open(my $fh, '<', 'filename') or die "Can't read file 'filename' [$!]\n";

Не выпадать, когда построчно выполняется обработка:

while (my $line = <$fh>) {
    # do something with $line
}

Использование обратных ссылок для извлечения данных из совпадений регулярных выражений:

if ($line =~ /color *: *(#[0-9a-fA-F]{6})/) {
    # color value is in $1
}

Сохраните имя класса во временной переменной, чтобы оно было у вас при совпадении с цветом:

if ($line =~ /^.(\w+) *\{/) {
    $class = $1;
}
2 голосов
/ 06 июня 2009

Для еще одного способа сделать это, вы можете попросить perl прочитать из файла разделы, отличные от строк, например, используя "}" в качестве разделителя записей.

my $color = "color:";

open (my $fh, '<', "index.html") || die "Can't open file: $!";  

{
    local $/ = "}";
    while( my $section = <$fh>) {  
    if($section =~ /$color(.*)/) {
        my ($selector) = $line =~ /(.*){/;
        print "$selector, $section\n";  
    }  
}

Непроверено! Кроме того, это, конечно, предполагает, что ваш CSS аккуратно заканчивает свои разделы отдельной строкой}.

2 голосов
/ 04 июня 2009

Ну, это не так просто, как кажется.

Классы CSS могут быть определены разными способами. Например,

    .classy {
         color: black;
    }

Удачи, используя построчный подход для анализа этого.

На самом деле, мой первый подход - поиск CPAN. Это выглядит многообещающе:

CSS - Объектно-ориентированный доступ к каскадным таблицам стилей (CSS)

Edit:

Я установил модули HTML :: TreeBuilder и CSS из CPAN и создал следующую аберрацию:

use strict;
use HTML::TreeBuilder;
use CSS;

foreach my $file_name (@ARGV) {
    my $tree = HTML::TreeBuilder->new; # empty tree
    $tree->parse_file($file_name);

    my $styles = $tree->find('style');

    if ($styles) {
        foreach my $style ($styles) {
            # This is an insane hack, not guarantee
            # to work in the future.
            my $css = CSS->new;
            $css->read_string(join "\n", @{$style->{_content}});

            print $css->output;
        }
    }
    $tree = $tree->delete;
}

Эта вещь печатает только все селекторы CSS из списка файлов HTML, но хорошо отформатирована, поэтому вы сможете продолжить отсюда.

1 голос
/ 06 июня 2009

У меня нет проблем с регулярным выражением, а скорее с захватом данных. Поскольку элементы CSS, как правило, состоят из нескольких строк, мне нужно выяснить, как создать массив между {и} с каждым переводом строки в качестве разделителя для элементов списка.

Нет, нет.

Для указанной выше задачи интересующими будут только строки, содержащие либо имя класса, либо определение цвета, а также, возможно, также строки, содержащие } для обозначения конца класса. Все остальные строки можно игнорировать, поэтому нет необходимости помещать их в массив.

Поскольку спецификации классов не могут быть вложенными [1], последний увиденный набор имен классов всегда будет активным набором классов. Следовательно, вам нужно записать только последний увиденный набор имен классов и, при обнаружении спецификации цвета, распечатать эти имена классов.

Есть все еще некоторые потенциальные трудности при обработке случаев, когда блок спецификации совместно используется несколькими классами (.foo, .bar, .baz { ... }), которые могут или не могут быть распределены по нескольким строкам, или если несколько атрибутов определены в одной строке, но разобраться с ними следует довольно легко из того, что я уже изложил. В зависимости от ваших входных данных вам также может потребоваться включить базовый механизм состояний, чтобы отслеживать, в комментариях вы или нет.

[1], т.е., хотя у вас могут быть семантически вложенные классы, такие как .foo и .foo .bar, они должны быть указаны в файле CSS как

.foo {
  ...
}
.foo .bar {
  ...
}

и не может быть

.foo {
  ...
  .bar {
    ...
  }
}
0 голосов
/ 04 июня 2009

Хотя я не тестировал код ниже, но что-то вроде этого должно работать:

if ($line =~ m/\.(.*?) \{(.*?)color:(.*?);(.*)/) {
 print "$1,$3\n";
}

Вы должны потратить некоторое время на изучение регулярных выражений для Perl.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...