Perl RegEx и цены продажи - PullRequest
       2

Perl RegEx и цены продажи

1 голос
/ 22 августа 2011

Я позаимствовал скрипт, используемый SteamCalculator.com , и хотел немного изменить его, чтобы захватить не только цену игр в Steam, но и цены продажи (если они существуют)

Код был чрезвычайно простым и достаточно легким для чтения.Чтобы узнать цену, которую он просматривает в HTML, с помощью функции поиска steampowered.com, извлекает все, что находится между <div class=\"col search_price\"> и </div>, затем выполняет следующую подпрограмму:

sub formPrice($)
{
    my $price = shift;

    if($price =~ m/(\d+)(?:\.|,)(\d{2})/)
    {
        return $1.$2;
    }
    else
    {
        return 0;
    }
}

Цена можетпринять одну из 4 форм, в зависимости от кода страны, в которой вы ищете цены, и от того, продается игра или нет.Вот эти четыре формы:

$9.99
<span><strike>$9.99</strike></span><br>$8.99
9,99£
<span><strike>9.99£</strike></span><br>8,99£

Как вы можете видеть, независимо от того, какую форму принимает цена, его скрипт будет захватывать самый первый экземпляр (\d+) (первая группа цифр, возвращая 9 в каждомрегистр), а также (\d{2}) (группа из 2 цифр) после \.|, (точка или запятая).Когда они объединяются, подпрограмма всегда возвращает 999, независимо от того, какой из четырех форматов имеет цена.

Я пытался найти способ изменить эту подпрограмму, чтобы вернуть 999 в случаях 1 и 3, но верните 899 в случаях 2 и 4. До сих пор я пытался:

1:

if((reverse $price) =~ m/(\d+)(?:\.|,)(\d{2})/g){
    return $2.$1;
}

2:

if($price =~ m/.*?(\d+)(?:\.|,)(\d{2})/g){
    return $1.$2;
}

3:

if($price =~ m/.*?(\d+)(?:\.|,)(\d{2})$/){
    return $1.$2;
}

Первые возвращенные цены, такие как 9199 за $19.99.Второй .*? все еще был жадным и возвращал 999 для $19.99.Третий вернул 0 в случаях 3 и 4 (дело с евро)

Ответы [ 3 ]

2 голосов
/ 22 августа 2011

Закрепление конца, как предлагает Флимзи, - самое простое решение.

Мне любопытно, чего вы пытались достичь со своей второй попыткой:

if($price =~ m/.*?(\d+)(?:\.|,)(\d{2})/g){
    return $1.$2;
}

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

if ( $price =~ m/.*\b(\d+)(?:\.|,)(\d{2})/ ) {
    return $1.$2;
}
0 голосов
/ 22 августа 2011

Вот способ сделать это с помощью глобальной опции:

sub price {
    my $str = shift;
    my @nums = $str =~ /(\d+)[.,]*(\d{2})/g;
    return 0 unless @nums;
    return (join '', @nums[-2,-1]);
}

Глобальный /g возвращает все совпадения в списке. Подпрограмма возвращает 0, если совпадений не найдено, иначе возвращается два последних, объединенных в строку. Использование [.,]* вместо предвкушения.

Обновление (на основе комментариев):

Немного более быстрое решение: чтение с конца строки и непосредственное использование строки вместо копирования.

sub price {
    return (join '', $_[0] =~ /(\d+)[.,](\d{2})\D*$/);
}
0 голосов
/ 22 августа 2011

Мне кажется, это работает:

m/(\d+)(?:\.|,)(\d{2})£?\s*$/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...