Проблемы с получением регулярных выражений для работы - PullRequest
1 голос
/ 30 января 2011

Я пытаюсь использовать регулярные выражения для удаления определенных блоков кодирования из текстового файла.До сих пор большинство моих строк регулярного выражения работали над удалением кодов.Однако у меня есть два вопроса:

1) Всякий раз, когда я удаляю кусок текста, где текст должен был быть, заменяется пустым пространством, а не просто удаляется.Пример моего кода регулярного выражения:

$file =~ s/<ul(.*)>//gi;

, который удаляет все строки в базовом формате <ul...>, что я и хочу.Однако, как упоминалось ранее, он заменяет тег и все содержащиеся в нем данные пробелами, и мне было интересно, как остановить эту конкретную подстановку.

2) Некоторые коды регулярных выражений, которые должны работать, похоже, не работают,Например, я хочу удалить

<script type="text/javascript"> 

function getCookies() { return ""; }

</script>

Я пытался использовать различные коды регулярных выражений, но, похоже, ничего не удаляет эти строки.Например:

$file =~ s/<script type(.*)<\/script>//gi;

, который удаляет теги <script type...> и </script> соответственно, но оставляет

function getCookies() { return ""; }

... без изменений.Я не уверен, почему это происходит, и я очень хотел бы исправить это.Как это было бы возможно?Любая помощь по любому из этих двух вопросов была бы чрезвычайно полезной!

Редактировать: Извините, я использую Perl!Кроме того: я только что попытался использовать

$file =~ /<script type(.*)<\/script>/sgi

..., а также / msgi, но, к сожалению, ни один из них не сработал.Теги <script type> и </script> были удалены, но по какой-то причине секция

function getCookies() { return ""; } 

... осталась.Вот весь мой код, включая все регулярные выражения:

use strict;
use warnings;

my $firstarg;
if ($ARGV[0]){
  $firstarg = $ARGV[0];
}

open (DATA, $ARGV[1]);
my $file = do {local $/; <DATA>};

$file =~ s/<\!DOCTYPE(.*)>//gi;
$file =~ s/<html>//gi;
$file =~ s/<\/html>//gi;
$file =~ s/<title>//gi;
$file =~ s/<\/title>//gi;
$file =~ s/<head>//gi;
$file =~ s/<\/head>//gi;
$file =~ s/<link(.*)>//gi;
$file =~ s/<\link>//gi;
$file =~ s/CDM(.*)\;//gi;
$file =~ s/<\!(.*)->//gi;
$file =~ s/<body(.*)>//gi;
$file =~ s/<\/body>//gi;
$file =~ s/<div(.*)>//gi;
$file =~ s/<\/div>//gi;
$file =~ s/function(.*)>//gi;
$file =~ s/<noscript>//gi;
$file =~ s/<\/noscript>//gi;
$file =~ s/<a(.*)>//gi;
$file =~ s/<\/a>//gi;
$file =~ s/<ul(.*)>//gi;
$file =~ s/<\/ul>//gi;
$file =~ s/<li(.*)>//gi;
$file =~ s/<\/li>//gi;
$file =~ s/<form(.*)>//gi;
$file =~ s/<\/form>//gi;
$file =~ s/<iframe(.*)>//gi;
$file =~ s/<\/iframe>//gi;
$file =~ s/<select(.*)>//gi;
$file =~ s/<\/select>//gi;
$file =~ s/<textarea(.*)>//gi;
$file =~ s/<\/textarea>//gi;
$file =~ s/<b>//gi;
$file =~ s/<\/b>//gi;
$file =~ s/<H1>//gi;
$file =~ s/<H2>//gi;
$file =~ s/<H3>//gi;
$file =~ s/<H4>//gi;
$file =~ s/<H5>//gi;
$file =~ s/<H6>//gi;
$file =~ s/<\/H1>//gi;
$file =~ s/<\/H2>//gi;
$file =~ s/<\/H3>//gi;
$file =~ s/<\/H4>//gi;
$file =~ s/<\/H5>//gi;
$file =~ s/<\/H6>//gi;
$file =~ s/<option(.*)>//gi;
$file =~ s/<\/option>//gi;
$file =~ s/<p>//gi;
$file =~ s/<\/p>//gi;
$file =~ s/<span(.*)>//gi;
$file =~ s/<\/span>//gi;
$file =~ s/<!doctype(.*)>//gi;
$file =~ s/<base(.*)>//gi;
$file =~ s/<br>//gi;
$file =~ s/<hr>//gi;
$file =~ s/<img(.*)>//gi;
$file =~ s/<input(.*)>//gi;
$file =~ s/<link(.*)>//gi;
$file =~ s/<meta(.*)>//gi;
$file =~ s/<script type(.*)<\/script>//gi;
print $file;

Хорошо, теперь, когда я удалил регулярное выражение <script>, которое вызывало одну проблему, была создана другая - с помощью:

$file =~ s/<script type(.*)<\/script>//gi;

удаляет все, что находится между первым экземпляром <script ...>, но не сам тег, не повторения тега во всем.Использование:

$file =~ s/<script type(.*)<\/script>//mgi;

приводит к точно так же.Использование:

$file =~ s/<script type(.*)<\/script>//sgi;

приводит к печати нескольких символов новой строки, но без другого текста, то же самое для /msgi.Ух, проблемы никогда не заканчиваются ...: (*

NEW EDIT: Я хотел бы извиниться за публикацию вопроса о разборе HTML с помощью регулярных выражений. Я понимаю, что в сообществе программистов есть довольно большая обратная реакцияпопрактиковаться (или попытаться попрактиковаться, так как это, похоже, чаще всего дает сбой, чем нет). Однако я, к сожалению, вынужден использовать регулярные выражения для разбора selected HTML, которые можно будет удалить, если большинствоне все теги HTML. Мне не разрешено использовать модуль, несмотря на то, что это самый очевидный и самый простой из ответов.

Ответы [ 5 ]

1 голос
/ 30 января 2011

Если вам запрещено использовать что-либо, кроме регулярных выражений Perl, вы можете адаптировать код для удаления тегов HTML из текста :

#!/usr/bin/perl -w
use strict;
use warnings;

$_ = do { local $/; <DATA> };

# see http://www.perlmonks.org/?node_id=161281
# ALGORITHM:
#   find < ,
#       comment <!-- ... -->,
#       or comment <? ... ?> ,
#       or one of the start tags which require correspond
#           end tag plus all to end tag
#       or if \s or ="
#           then skip to next "
#           else [^>]
#   >
s{
  <               # open tag
  (?:             # open group (A)
    (!--) |       #   comment (1) or
    (\?) |        #   another comment (2) or
    (?i:          #   open group (B) for /i
      (           #     one of start tags
        SCRIPT |  #     for which
        APPLET |  #     must be skipped
        OBJECT |  #     all content
        STYLE     #     to correspond
      )           #     end tag (3)
    ) |           #   close group (B), or
    ([!/A-Za-z])  #   one of these chars, remember in (4)
  )               # close group (A)
  (?(4)           # if previous case is (4)
    (?:           #   open group (C)
      (?!         #     and next is not : (D)
        [\s=]     #       \s or "="
        ["`']     #       with open quotes
      )           #     close (D)
      [^>] |      #     and not close tag or
      [\s=]       #     \s or "=" with
      `[^`]*` |   #     something in quotes ` or
      [\s=]       #     \s or "=" with
      '[^']*' |   #     something in quotes ' or
      [\s=]       #     \s or "=" with
      "[^"]*"     #     something in quotes "
    )*            #   repeat (C) 0 or more times
  |               # else (if previous case is not (4))
    .*?           #   minimum of any chars
  )               # end if previous char is (4)
  (?(1)           # if comment (1)
    (?<=--)       #   wait for "--"
  )               # end if comment (1)
  (?(2)           # if another comment (2)
    (?<=\?)       #   wait for "?"
  )               # end if another comment (2)
  (?(3)           # if one of tags-containers (3)
    </            #   wait for end
    (?i:\3)       #   of this tag
    (?:\s[^>]*)?  #   skip junk to ">"
  )               # end if (3)
  >               # tag closed
 }{}gsx;         # STRIP THIS TAG

print;

__END__
<html><title>remove script, ul</title>
<script type="text/javascript"> 

function getCookies() { return ""; }

</script>
<body>
<ul><li>1
<li>2
<p>paragraph

Вывод

remove script, ul


1
2
paragraph

ПРИМЕЧАНИЕ. Это регулярное выражение не работает для вложенных контейнеров тегов, например:

<!DOCTYPE html>
<meta charset="UTF-8">
<title>Nested &lt;object> example</title>
<body>
<object data="uri:here">fallback content for uri:here
  <object data="uri:another">uri:another fallback
  </object>!!!this text should be striped too!!!
</object>

Вывод

Nested &lt;object> example

!!!this text should be striped too!!!

Не анализировать HTML срегулярные выражения. Используйте html-анализатор или инструмент, построенный поверх него, например, HTML::Parser:

#!/usr/bin/perl -w
use strict;
use warnings;

use HTML::Parser ();

HTML::Parser->new(
    ignore_elements => ["script"],
    ignore_tags => ["ul"],
    default_h => [ sub { print shift }, 'text'],
    )->parse_file(\*DATA) or die "error: $!\n";

__END__
<html><title>remove script, ul</title>
<script type="text/javascript"> 

function getCookies() { return ""; }

</script>
<body>
<ul><li>1
<li>2
<p>paragraph

Output

<html><title>remove script, ul</title>

<body>
<li>1
<li>2
<p>paragraph
1 голос
/ 30 января 2011

Чтобы ответить на ваш последний комментарий:

perl -e'$file="<script etc>\nfoo\n</script>bar"; $file =~ s/<script.*script>//gis; print $file'

похоже, что это делает то, что вы хотите, как это предлагают другие. Я не понимаю, как это отличается от того, что вы пытаетесь.

....

Можете ли вы добавить это:

use Data::Dumper;
$Data::Dumper::Useqq=1;
print Dumper($file);

перед регулярным выражением и дайте нам результат?

.....

Бинго:

строки 5 и 6 вашего списка $ file = ~ уже отфильтровали их:

$file =~ s/<\!DOCTYPE(.*)>//gi;
$file =~ s/<html>//gi;
$file =~ s/<\/html>//gi;
$file =~ s/<title>//gi;
$file =~ s/<\/title>//gi;
## Here they come:
$file =~ s/<script(.*)>//gi;
$file =~ s/<\/script>//gi;
$file =~ s/<head>//gi;
1 голос
/ 30 января 2011

Я не уверен, какой язык программирования вы используете, но, предполагая, что вы используете Perl, попробуйте поместить модификатор s в конце регулярного выражения:

$file =~ /<script type(.*)<\/script>/sgi

The *Модификатор 1005 * заставляет . соответствовать любому символу, включая символы новой строки (обычно он не включает символы новой строки)


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

$file =~ s/<script type(.*)<\/script>/sgi

, чтобы удалить все, включая теги сценария.Однако, если вы просто хотите, чтобы содержимое между тегами было:

$file =~ s/(<script type="[^"]*"\s*>).*(<\/script>)/$1$2/sgi;

Обратите внимание на $1$2 между слешами.Этот текст является текстом замены.В этом случае мы используем текст из групп захвата вместо оригинала.В вашем вопросе вы использовали две косые черты подряд (s/<ul(.*)>//gi), что означает, что вы заменяете все совпадение пустой строкой.Мне кажется, что вы действительно хотите заменить все пустым пространством (ASCII 20), например s/<ul(.*)>/ /gi.


Со времени вашего последнего редактирования - Вы захотитеиспользовать одно регулярное выражение для сценариев, так как вам не нужно содержимое:

$file =~ s/(<script type="[^"]*"\s*>).*(<\/script>)/ /sgi;

и другое универсальное регулярное выражение для всех остальных тегов:

$file =~ s/<\/?\s*[^>]+>//sgi

Я предполагаю, что здесьВы не хотите ограничивать только показанные вами теги, вы просто хотите убить весь HTML.Для этого есть утилита * nix html2text .Возможно, вы захотите использовать это.

0 голосов
/ 30 января 2011

Это:

$file =~ s/<div(.*)>//gi;

не будет делать то, что вы ожидаете. Оператор '*' жадный. Если у вас есть строка вроде:

hello<div id="foo"><b>bar!</b>baz

он заменит столько, сколько сможет, оставив только:

hellobaz

Вы хотите:

$file =~ s/<div[^>]*>//gi;

или

$file =~ s/<div.*?>//gi;
0 голосов
/ 30 января 2011

Вы должны быть намного осторожнее, чем это.См. Оба подхода в этом ответе .

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