Модераторы: ginnie

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Скобка в теге пропущена 
:(
    Опции темы
Сisa
Дата 16.12.2014, 21:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 179
Регистрация: 18.1.2013

Репутация: нет
Всего: нет



Для любого парного тега хтмл 
Код

<span>abcd/span>
<div>abcd/div>


и т.п. с произвольным содержимым внутри тега нужно вставить пропущенную скобку < с помощью регулярного выражения perl :

Код

$tmp=qq~<span>abcd/span>~;
print "$tmp\n";
$tmp =~ s/(<[^>]+>[^<]+)(<)/$1\/>$2/g;
print "$tmp\n";

и не получается :(
Поможете?

Это сообщение отредактировал(а) Сisa - 16.12.2014, 22:40
PM MAIL   Вверх
tzirechnoy
Дата 16.12.2014, 22:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: нет
Всего: 16



Этому регекспу для соответствия надо два знака меньшэ -- тот, что первым символом в первом  подвыражэнии, и тот, что единственным символом во втором.
А в строке знак меньшэ -- один. Так что он и не получается.
PM MAIL   Вверх
Сisa
Дата 16.12.2014, 22:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 179
Регистрация: 18.1.2013

Репутация: нет
Всего: нет



Прошу прощения, что получилось так, что я отредактировал свое сообщение после Вашего ответа.

Добавлено @ 22:52
Код

$tmp =~ s/<([^>]+)>([^$1]>)/<$1>$2<$1>/gi;

Если бы такое получилось smile  т.е. так же нельзя в левой части употреблять $1  а то бы наверно заработало ?

Это сообщение отредактировал(а) Сisa - 16.12.2014, 22:55
PM MAIL   Вверх
Сisa
Дата 17.12.2014, 00:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 179
Регистрация: 18.1.2013

Репутация: нет
Всего: нет



Код

sub a{
 my $tmp=shift;
 my $tmp3="$tmp";
 $tmp=~ /<([^>]+)>/;
 my $tmp2=$1;              #my @r=split($tmp2,$tmp);#print "--@r\n";
 #$tmp3 =~ /<$tmp2>([^$tmp2]+)$tmp2>/;
 $tmp3 =~ /<$tmp2>([^<>]+)$tmp2>/;
 $tmp3=$1;
 $tmp =~ s/<$tmp2>[^>]+$tmp2>/<$tmp2>$tmp3<\/$tmp2>/g;
 return $tmp;
}


print &a('vhg<span>ab555cdspan>56')." ok!\n";
print &a('vhg<div>ab555cddiv>56')." ok!\n \n";

print &a('vhg<span>abcdspan>5645454545<span>abcn/span>4545<div>ygrdresdiv>787878')."\n \n";

print &a(&a('vhg<span>abcdspan>5645454545<span>abcn/span>4545<div>ygrdresdiv>787878'))."\n \n";

$b='hghg<div>89540div>vh15g<span>abcd/span>5645454545<span>abcnspan>4545<div>ygrdresdiv>787878';
$b=&a($b);
print "$b\n";

$b=&a($b);
print "$b ???????\n";


Как то все не так. Для простых строк работает (первых двух),  а чуть сложнее уже ошибки. 
Это не регулярное выражение в одну строку. 
А если уже функция, и вовсе без регулярных наверно можно через сплит-джоин.
А нужно то ведь для много строчного аргумента, где начало тега в одной строке, а парный тег в другой может быть, тем более тег с пропущенным символом < может содержать другие теги.
PM MAIL   Вверх
ginnie
Дата 17.12.2014, 18:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 1
Всего: 49



Сisa, если я правильно понял задание, вот мой вариант  smile

Код

#!/usr/bin/perl

use v5.18;

my @strings = ('vhg<span>ab555cdspan>56', 'vhg<div>ab555cddiv>56',
               'vhg<span>abcdspan>5645454545<span>abcn/span>4545<div>ygrdresdiv>787878',
               'hghg<div>89540div>vh15g<span>abcd/span>5645454545<span>abcnspan>4545<div>ygrdresdiv>787878');
for my $string (@strings) {
    state $tags_levels = {};
    $string =~ s{(?'tag'<(?'tag_name'\w+).*?>)|(?'tag'(?'tag_start'<?/)(?'tag_name'\w+)>)}
    {
        ($+{tag_start} and $+{tag_start} eq '/')
        ? ($tags_levels->{$+{tag_name}} ? do { $tags_levels->{$+{tag_name}}--; '</'.$+{tag_name}.'>' } : $+{tag})
        : do { $tags_levels->{$+{tag_name}} += $+{tag_start} ? -1 : 1; $+{tag} }
    }eg;
}

local $, = $/;
say @strings;


Это сообщение отредактировал(а) ginnie - 17.12.2014, 19:04


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
Сisa
Дата 17.12.2014, 21:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 179
Регистрация: 18.1.2013

Репутация: нет
Всего: нет



ginnie,  ведь не работает?

say @strings;
print @strings;

PM MAIL   Вверх
ginnie
Дата 17.12.2014, 23:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 1
Всего: 49



Сisa, можно поконкретнее написать, что не работает?
Я сейчас новые для себя конструкции в Perl осваиваю, поэтому код получился довольно нетрадиционный.

Это сообщение отредактировал(а) ginnie - 17.12.2014, 23:23


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
Сisa
Дата 17.12.2014, 23:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 179
Регистрация: 18.1.2013

Репутация: нет
Всего: нет



Код

use v5.18;
my @strings = ('vhg<span>ab555cdspan>56',
               'vhg<div>ab555cddiv>56',
               'vhg<span>abcdspan>5645454545<span>abcn/span>4545<div>ygrdresdiv>787878',
               'hghg<div>89540div>vh15g<span>abcd/span>5645454545<span>abcnspan>4545<div>ygrdresdiv>787878');
for my $string (@strings) {
    state $tags_levels = {};
    $string =~ s{(?'tag'<(?'tag_name'\w+).*?>)|(?'tag'(?'tag_start'<?/)(?'tag_name'\w+)>)}
    {
        ($+{tag_start} and $+{tag_start} eq '/')
        ? ($tags_levels->{$+{tag_name}} ? do { $tags_levels->{$+{tag_name}}--; '</'.$+{tag_name}.'>' } : $+{tag})
        : do { $tags_levels->{$+{tag_name}} += $+{tag_start} ? -1 : 1; $+{tag} }
    }eg;
}
local $, = $/;
say @strings;
print "\n \n \n";
print @strings;


#vhg<span>ab555cdspan>56
#vhg<div>ab555cddiv>56
#vhg<span>abcdspan>5645454545<span>abcn</span>4545<div>ygrdresdiv>787878
#hghg<div>89540div>vh15g<span>abcd</span>5645454545<span>abcnspan>4545<div>ygrdresdiv>787878

#vhg<span>ab555cdspan>56
#vhg<div>ab555cddiv>56
#vhg<span>abcdspan>5645454545<span>abcn</span>4545<div>ygrdresdiv>787878
#hghg<div>89540div>vh15g<span>abcd</span>5645454545<span>abcnspan>4545<div>ygrdresdiv>787878

Символ < не восстанавливается? Цель его восстановить, потому что он пропущен в разных тегах длинного хтмл.
PM MAIL   Вверх
ginnie
Дата 17.12.2014, 23:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 1
Всего: 49



Сisa, я делал по условию, что восстанавливаться треугольная скобка должна в парных тегах, где только её нет (а слеш есть), т.е. в примере в двух последних строках.
Я во всех вариантах не проверял, просто подкинул Вам идею и реализацию.

Это сообщение отредактировал(а) ginnie - 17.12.2014, 23:56


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
Сisa
Дата 18.12.2014, 00:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 179
Регистрация: 18.1.2013

Репутация: нет
Всего: нет



ginnie спасибо! все работает! и с разными тегами одновременно!
Правда непонятно как все устроено, но ведь работает! 
Надо будет разобрать по буквам smile
PM MAIL   Вверх
ginnie
Дата 18.12.2014, 00:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 1
Всего: 49



Сisa, сегодня уже поздно, я завтра все подробно опишу.


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
Сisa
Дата 18.12.2014, 12:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 179
Регистрация: 18.1.2013

Репутация: нет
Всего: нет



Код

use v5.18;
my @strings = ('vhg<span>ab555cdspan>56',
               'vhg<div>ab555cddiv>56',
               'vhg<span>abcdspan>5645454545<span>abcn/span>4545<div>ygrdresdiv>787878',
               'hghg<div>89540div>vh15g<span>ab7700cd/span>5645454545<span>abcnspan>4545<div>ygrdresdiv>787878');
print @strings;
print "\n \n \n";
for my $string (@strings) {
    state $tags_levels = {};
    $string =~ s{(?'tag'<(?'tag_name'\w+).*?>)|(?'tag'(?'tag_start'<?/)(?'tag_name'\w+)>)}
    {
        ($+{tag_start} and $+{tag_start} eq '/') ?
             ($tags_levels->{$+{tag_name}} ?
         do { $tags_levels->{$+{tag_name}}--; '</'.$+{tag_name}.'>' } : $+{tag}) :
         do { $tags_levels->{$+{tag_name}} += $+{tag_start} ? -1 : 1; $+{tag} }
    }eg;

    print " \n".$+{tag_start}.'   111 '.$+{tag_name}.'  222  ' .$+{tag}.' 333  '.  $tags_levels.  " \n";
    while(my($key,$value) = each $tags_levels){
         print "$key => $value \n";
    };

}
local $, = $/;
print "\n \n \n";
print @strings;


Центр внимания (и наверно не только моего)  переместился с моего вопроса на Ваш подход в работающем решении, т.е. уже даже больше интересно как Вы все это составили?
и как можно модифицировать скрипт.
(подробности хорошо бы)

PM MAIL   Вверх
ginnie
Дата 18.12.2014, 22:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 1
Всего: 49



Прошу прощения за задержку!

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

#!/usr/bin/perl
use v5.18;
my @strings = ('vhg<span>ab555cdspan>56', 'vhg<div>ab555cddiv>56',
               'vhg<span>abcdspan>5645454545<span>abcn/span>4545<div>ygrdresdiv>787878',
               'hghg<div>89540div>vh15g<span>abcd/span>5645454545<span>abcnspan>4545<div>ygrdresdiv>787878');
for my $string (@strings) {
    my %tags_levels;
    $string =~ s{(?'tag'<(?'tag_name'\w+).*?>)|(?'tag'(?'tag_start'<?/)(?'tag_name'\w+)>)}
    {
        ($+{tag_start} and $+{tag_start} eq '/')
        ? ($tags_levels{$+{tag_name}} ? do { $tags_levels{$+{tag_name}}--; '<'.$+{tag} } : $+{tag})
        : do { $tags_levels{$+{tag_name}} += $+{tag_start} ? -1 : 1; $+{tag} }
    }eg;
}
local $, = $/;
say @strings;


Чтобы обрабатывать парные теги, надо считать открывающие теги и закрывающие, для этого будем использовать хэш %tags_levels, ключами будут названия тегов.
Решение задачи я сделал через регулярное выражение подстановки s///, когда регулярное выражение содержит символ '/', я обычно использую фигурные скобки в качестве ограничителей s{}{}.
Для поиска открывающих и закрывающих тегов я использовал разные регулярные выражения: (?'tag'<(?'tag_name'\w+).*?>) и (?'tag'(?'tag_start'<?/)(?'tag_name'\w+)>), объединив их структурирующим метасимволом |. В этих регулярых выражениях захват подстроки я сделал с использованием именованных групп, чтобы можно было удобно обращатся с захваченному тексту по имени $+{group_name}, вместо обычного индекса $1, $2 и т.п. Т.е. вышеуказанные выражения эквивалентны (<(\w+).*?>) и ((<?/)(\w+)>), но использовать $1, $2 и $3 мне не так удобно.
В секции замены я использовал Perl-код для анализа захваченного текста, поэтому для его выполнения в регулярном выражении необходимо добавить модификатор /e. Еще нужен модификатор /g для того, чтобы поиск и замена продолжались многократно, до самого конца строки.
При нахождении открывающего тега инкрементируем значение ключа с именем тэга в хэше и заменяем подстроку с тэгом на нее же, т.к. никакие изменения нам не нужны.
При нахождении закрывающего тега сначала проверяем, является ли он парным, для этого проверяем значение ключа в хэше, если тег не парный (значение равно 0 или неопределено), не обрабытываем его, заменяя найденную подстроку на нее саму. Если же тег парный, декрементируем значение в кэше для имени тега, проверяем наличие открывающей угловой скобки: если ее нет, то добавляем, если нет, то берем захваченный текст без изменений и заменяем им исходный.

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

Это сообщение отредактировал(а) ginnie - 18.12.2014, 22:23


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
Сisa
Дата 20.12.2014, 17:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 179
Регистрация: 18.1.2013

Репутация: нет
Всего: нет



Комментарий помогает, особенно то, как он изложен. 
Что код, что комментарий- все отлично.
ginnie спасибо! 
PM MAIL   Вверх
Сisa
Дата 21.12.2014, 12:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 179
Регистрация: 18.1.2013

Репутация: нет
Всего: нет



Код

#!/usr/bin/perl
my @strings = ('vhg<span>ab555cdspan>56', 'vhg<div>ab555cddiv>56','vhg<span>abcdspan>5645454545<span>abcn/span>4545<div>ygrdresdiv>787878','hghg<div>89540div>vh15g<span>ab111111cd/span>5645454545<span>abcnspan>4545<div>ygr22222222dres/div>787878');
print @strings; print "\n \n";
for my $string (@strings) { my %tags_levels;
    $string =~ s{(?'tag'<(?'tag_name'\w+).*?>)|(?'tag'(?'tag_start'<?/)(?'tag_name'\w+)>)} {
        ($+{tag_start} and $+{tag_start} eq '/')
        ? ($tags_levels{$+{tag_name}} ? do {
            $tags_levels{$+{tag_name}}--; '<'.$+{tag} } : $+{tag})
        : do { $tags_levels{$+{tag_name}} += $+{tag_start} ? -1 : 1; $+{tag} }
    }eg;
} print @strings,"\n";
@strings = ('vhg<span>ab555cdspan>56', 'vhg<div>ab555cddiv>56','vhg<span>abcdspan>5645454545<span>abcn/span>4545<div>ygrdresdiv>787878','hghg<div>89540div>vh15g<span>ab111111cd/span>5645454545<span>abcnspan>4545<div>ygr22222222dres/div>787878');
for my $string (@strings) {my %tags_levels;
    $string =~ s{(<(\w+).*?>)|((<?/)(\w+)>)}{
         ($4 and $4 eq '/')?
          ($tags_levels{$5} ?
           do{
             $tags_levels{$5}--;
             '<'.$3
           }:''
          )
        :do{$tags_levels{$2} += $4?-1:1; $1}
    }eg;
} print @strings,"\n";
@strings = ('vhg<span>ab555cdspan>56', 'vhg<div>ab555cddiv>56','vhg<span>abcdspan>5645454545<span>abcn/span>4545<div>ygrdresdiv>787878','hghg<div>89540div>vh15g<span>ab111111cd/span>5645454545<span>abcnspan>4545<div>ygr22222222dres/div>787878');

for my $string (@strings){
 $string =~ s/(<?\/)(\w+)>/<\/$2>/gm;
} print @strings,"\n";

Использование  $+{group_name} или $1,$2,$3,$4,$5 и правда имеет свои отличия, но оба полезны для обучения.
Последний вариант самый короткий, но как то приспособить его к восстановлению пропущенных символов  </ а не только < наверно не получится, тут без Вашей конструкции с tags_levels не обойтись.
А сделать вариант без полной замены, только поиском определять и сохранять позиции, в которые нужно вставить отсутствующие угловые скобки, и после завершения поиска, выполнить вставку скобок в исходную строку не сделаю т.к. не представляю себе его. Буду попробовать все же как то восстанавливать  и  < и  </ для многострочного текста в одной конструкции  с tags_levels или  $1,$2,$3,$4,$5.
PM MAIL   Вверх
Сisa
Дата 21.12.2014, 15:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 179
Регистрация: 18.1.2013

Репутация: нет
Всего: нет



Код

#!/usr/bin/perl
use v5.18;
my @strings = ('vhg<span>ab555cdspan>',
               '<div>ab555cddiv>',
               '<span>abcdspan><span>abcn/span><div>ygrdresdiv>',
               '<div>89540div><span>ab111111cd/span><span>abcnspan><div>ygr22222222dres/div>');
print @strings,"\n";
for my $string (@strings) {my($s,$s2,$s3);
    $string =~ s{(<(\w+).*?>)|((<?)(/?)(\w+)>)}{
      ($6 and $s)?
        do{
           (!$5 and !$4 )?
             do{
                 $s2=$s;
                 $s3=$s;
                 $s='';
                 $s2=(split($s2,$6))[0];
                $s2.'</'.$s3.'>'
             }:
             do{
              ($5 eq '/' and !$4)?
                do{
                 $s2=$s;
                 $s3=$s;
                 $s='';
                 '</'.$s3.'>'
                }:
                $1
             }
        }:do{
         $s = $2;
         $1
        }
    }eg;
}  print @strings,"\n";


Это сообщение отредактировал(а) Сisa - 21.12.2014, 15:56
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Регулярные выражения | Следующая тема »


 




[ Время генерации скрипта: 0.1542 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.