Передача regex замены как переменная в Perl?

Как насчет этого?

answer = int(input("What should the answer be? "))
guesses = int(input("How many guesses? "))
guess_count = 1
guess_correct = False

while guess_correct is False:
    if guess_count < guesses:
        guess = int(input("Guess a number: "))
        if answer < guess:
            print("The number is lower than that.")
        elif answer > guess:
            print("The number is higher than that")
        else:  # answer == guess
            print("You win!")
            break
        guess_count += 1
    elif guess_count == guesses:
        guess = int(input("Guess a number: "))
        if guess != answer:
            print("You lose; the number was " + str(answer) + ".")
        if guess == answer:
            print("You win!")
        break

Это очень похоже на вашу программу, но там есть пара break операторов. Это говорит Python немедленно прекратить выполнение этого цикла и перейти к следующему блоку кода (в данном случае ничего). Таким образом, вам не нужно ждать, пока программа оценит условия, указанные вами для цикла while, прежде чем начинать следующий цикл. Если это помогло решить вашу проблему, было бы здорово, если бы вы щелкнули галочку напротив моего сообщения

.
23
задан ceo 24 September 2008 в 03:00
поделиться

6 ответов

Я должен передать regex замену как переменную

Вы? Почему бы не передать ссылку кода? Пример:

sub modify
{
  my($text, $code) = @_;
  $code->($text);
  return $text;
}

my $new_text = modify('foo baz', sub { $_[0] =~ s/foo/bar/ });

В целом, когда Вы хотите передать "что-то, что делает что-то" к подпрограмме ("regex замена" в случае Вашего вопроса), ответ должен передать ссылку на часть кода. Perl Высшего порядка является хорошей книгой по теме.

32
ответ дан 29 November 2019 в 01:10
поделиться

Ну, можно предварительно скомпилировать РЕ с помощью qr//оператор. Но Вы не можете передать оператор (s///).

$pattern = qr/foo/;

print "match!\n" if $text =~ $pattern;

, Но если необходимо передать оператор замены, Вы - до передачи или код или строки:

proc('$text =~ s/foo/bar');

sub proc { 
   my $code = shift;

   ...

   eval $code;
}

или, код:

proc(sub {my $text = shift;  $text =~ s/foo/bar});

sub proc {
   my $code = shift;

   ...

   $code->("some text");
}
8
ответ дан 29 November 2019 в 01:10
поделиться
sub proc {
    my($match, $subst) = @_;
    my $txt = "foo baz";
    $txt =~ s/$match/$subst/;
    print "$txt\n";
}

my $matcher = qr/foo/;
my $sub_str = "bar";

proc($matcher, $sub_str);

Это скорее непосредственно отвечает на Ваш вопрос. Можно сделать более - но когда я использовал qr//термин вместо $sub_str как простой литерал, затем расширенным regex заменили.

Я недавно должен был создать синтаксический анализатор (тестовый синтаксический анализатор) для операторов с некоторыми странными (диалект) типы SQL, распознав строки, такие как это, разделив его на три имен типов:

input: datetime year to second,decimal(16,6), integer

Сценарий я раньше демонстрировал используемый, заключил regexes в кавычки.

#!/bin/perl -w
use strict;
while (<>)
{
    chomp;
    print "Read: <$_>\n";
    my($r1) = qr%^input\s*:\s*%i;
    if ($_ =~ $r1)
    {
        print "Found input:\n";
        s%$r1%%;
        print "Residue: <$_>\n";
        my($r3) = qr%(?:year|month|day|hour|minute|second|fraction(?:\([1-5]\))?)%;
        my($r2) = qr%
                        (?:\s*,?\s*)?   # Commas and spaces
                        (
                            (?:money|numeric|decimal)(?:\(\d+(?:,\d+)?\))?   |
                            int(?:eger)?  |
                            smallint      |
                            datetime\s+$r3\s+to\s+$r3
                        )
                    %ix;
        while ($_ =~ m/$r2/)
        {
            print "Got type: <$1>\n";
            s/$r2//;
        }
        print "Residue 2: <$_>\n";
    }
    else
    {
        print "No match:\n";
    }
    print "Next?\n";
}

Мы можем спорить об использовании имен как $r1 и т.д. Но это сделало задание... это не было и не, производственный код.

8
ответ дан 29 November 2019 в 01:10
поделиться

eval "$txt =~ $pattern";
Это становится
eval "\"foo baz\" =~ s/foo/bar/"
и замены не работают над литеральными строками.

Это работало бы:

eval "\$txt =~ $pattern"
но это не очень приятно. оценка почти никогда не является правильным решением.

решение zigdon может сделать что-либо, и решение Jonathan довольно подходит, если замещающая строка статична. Если бы Вы хотите что-то более структурированное, чем первое и более гибкое, чем второе, я предложил бы гибрид:

sub proc {
    my $pattern = shift;
    my $code = shift;
    my $txt = "foo baz";
    $txt =~ s/$pattern/$code->()/e;
    print "$txt\n";
}
my $pattern = qr/foo/;
proc($pattern, sub { "bar" });   # ==> bar baz
proc($pattern, sub { "\U$&" });  # ==> FOO baz
5
ответ дан 29 November 2019 в 01:10
поделиться

s/// не regex. Таким образом Вы не можете передать его как regex.

мне не нравится eval за это, это очень хрупко с большим количеством bordercases.

я думаю, лучше проявлять подход, подобный тому, который берет JavaScript: передайте обоих regex (в Perl, который является qr//), и ссылка кода для замены. Например, для передачи параметров для получения того же эффекта как [1 110]

s/(\w+)/\u\L$1/g;

можно звонить

replace($string, qr/(\w+)/, sub { "\u\L$1" }, 'g');

Примечание, что 'g' модификатор не является на самом деле флагом для regex (я думаю, присоединяя его к regex, ошибка дизайна в JavaScript), таким образом, я принял решение передать его в 3-м параметре.

, Как только API был решен, реализация может быть сделана затем:

sub replace {
    my($string, $find, $replace, $global) = @_;
    unless($global) {
        $string =~ s($find){ $replace->() }e;
    } else {
        $string =~ s($find){ $replace->() }ge;
    }
    return $string;
}

Позволяют нам попробовать его:

print replace('content-TYPE', qr/(\w+)/, sub { "\u\L$1" }, 'g');

Результат:

Тип контента

, Который выглядит хорошим мне.

5
ответ дан 29 November 2019 в 01:10
поделиться

Возможно, Вы могли бы заново продумать свой подход.

Вы хотите передать в функции regex замена, вероятно, потому что функция будет получать текст, на который будут управлять из некоторого другого источника (читающий из файла, сокета, и т.д.). Но Вы объединяете регулярное выражение с заменой регулярного выражения.

В выражении, s/foo/bar/, у Вас на самом деле есть регулярное выражение (" / нечто / ") и замена ("панель"), которая должна заменить то, что подобрано выражением. В подходах Вы попробовали к настоящему времени, Вы столкнулись с проблемами, пытающимися использовать eval, главным образом из-за вероятности специальных символов в выражении, что любой вмешивается в eval или будьте интерполированы (т.е. проглотил) в процессе оценки.

Таким образом вместо этого, попытайтесь передать свою стандартную программу два аргумента: выражение и замена:

sub apply_regex {
    my $regex = shift;
    my $subst = shift || ''; # No subst string will mean matches are "deleted"

    # some setup and processing happens...

    # time to make use of the regex that was passed in:
    while (defined($_ = <$some_filehandle>)) {
        s/$regex/$subst/g; # You can decide if you want to use /g etc.
    }

    # rest of processing...
}

Этот подход обладает дополнительным преимуществом: если Ваш regex шаблон не имеет никаких специальных символов в нем, можно просто передать его в непосредственно:

apply_regex('foo', 'bar');

Или, если это делает, можно использовать qr// оператор заключения в кавычки для создания объекта regex и передачи, что как первый параметр:

apply_regex(qr{(foo|bar)}, 'baz');
apply_regex(qr/[ab]+/, '(one or more of "a" or "b")');
apply_regex(qr|\d+|); # Delete any sequences of digits

Больше всего Вам действительно не нужно eval или использование code-references/closures для этой задачи. Это только добавит сложность, которая может сделать отладку тяжелее, чем это должно быть.

Randy

4
ответ дан 29 November 2019 в 01:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: