Встраивание оценок в регулярные выражения Perl - PullRequest
8 голосов
/ 15 июля 2010

Итак, я пишу быстрый Perl-скрипт, который очищает некоторый HTML-код и запускает его через программу html -> pdf.Я хочу потерять как можно меньше информации, поэтому я хотел бы расширить мои текстовые области, чтобы они соответствовали всему тексту, который в настоящее время находится в них.Это означает, что в моем случае установка числа строк в вычисляемое значение на основе значения строки внутри текстового поля.

В настоящее время это регулярное выражение, которое я использую

$file=~s/<textarea rows="(.+?)"(.*?)>(.*?)<\/textarea>/<textarea rows="(?{ length($3)/80 })"$2>$3<\/textarea>/gis;
* 1005.* К сожалению, Perl, похоже, не распознает то, что мне сказали, это синтаксис для встраивания кода Perl в регулярные выражения поиска и замены. Есть ли какие-нибудь любители Perl, желающие сказать мне, что я делаю неправильно?С уважением, Зак

Ответы [ 6 ]

11 голосов
/ 15 июля 2010

Шаблон (?{...}) - это экспериментальная функция для выполнения кода на стороне совпадения, но вы хотите выполнить код на стороне replace . Для этого используйте переключатель регулярного выражения /e:

#! /usr/bin/perl

use warnings;
use strict;

use POSIX qw/ ceil /;

while (<DATA>) {
  s[<textarea rows="(.+?)"(.*?)>(.*?)</textarea>] {
    my $rows = ceil(length($3) / 80);
    qq[<textarea rows="$rows"$2>$3</textarea>];
  }egis;
  print;
}

__DATA__
<textarea rows="123" bar="baz">howdy</textarea>

Выход:

<textarea rows="1" bar="baz">howdy</textarea>
6 голосов
/ 15 июля 2010

Синтаксис, который вы используете для встраивания кода, действителен только в части «соответствия» подстановки (левая сторона). Чтобы встроить код в правую часть (которая является обычной строкой в ​​двойных кавычках Perl), вы можете сделать это:

$file =~ s{<textarea rows="(.+?)"(.*?)>(.*?)</textarea>}
          {<textarea rows="@{[ length($3)/80 ]}"$2>$3</textarea>}gis;

При этом используется Perl идиома "some string @{[ embedded_perl_code() ]} more string".

Но если вы работаете с очень сложным оператором, может быть проще перевести подстановку в режим "eval", где она обрабатывает замещающую строку как код Perl:

$file =~ s{<textarea rows="(.+?)"(.*?)>(.*?)</textarea>}
          {'<textarea rows="' . (length($3)/80) . qq{"$2>$3</textarea>}}gise;

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

1 голос
/ 15 июля 2010

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

http://search.cpan.org/dist/HTML-Parser/Parser.pm

В противном случае вы рискуете отомстить Ктулу:

http://www.codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html

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

0 голосов
/ 23 февраля 2018

В соответствии с http://perldoc.perl.org/perlrequick.html#Search-and-replace, это может быть достигнуто с помощью " модификатора оценки s///e", например, у вас gis должен быть дополнительный e.

Модификатор оценки s /// e оборачивает eval {...} вокруг строки замещения, и вычисленный результат заменяется соответствующей подстрокой.Некоторые примеры:

# convert percentage to decimal
$x = "A 39% hit rate";
$x =~ s!(\d+)%!$1/100!e;       # $x contains "A 0.39 hit rate"
0 голосов
/ 15 июля 2010

Во-первых, вам нужно заключить в кавычки / внутри выражения в тексте замены (в противном случае perl будет видеть как оператор ///, за которым следует число 80 и так далее).Или вы можете использовать другой разделитель;для сложных подстановок подходящими являются подходящие скобки.

Тогда вы получите основную проблему, которая заключается в том, что (?{...}) доступно только в шаблонах.Текст замены не является шаблоном, это (почти) обычная строка.

Вместо этого есть оператор e для оператора s///, который позволяет вам писать выражение замены, а не строку замены.

$file =~ s(<textarea rows="(.+?)"(.*?)>(.*?)</textarea>)
          ("<textarea rows=\"" . (length($3)/80) . "\"$2>$3</textarea>")egis;
0 голосов
/ 15 июля 2010

Я полагаю, что ваша проблема не укрылась /

Если это не проблема, это, безусловно, проблема.

Попробуйте вместо этого, обратите внимание \/80

$file=~s/<textarea rows="(.+?)"(.*?)>(.*?)<\/textarea>/<textarea rows="(?{ length($3)\/80 })"$2>$3<\/textarea>/gis;

Основной шаблон для этого кода:

$file =~ s/some_search/some_replace/gis;

gis - это параметры, которые мне нужно найти.Я думаю, что g = глобально, i = без учета регистра, s = ничего не приходит в голову прямо сейчас.

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