2013-07-31 2 views
1

Я спросил в другой теме о сопоставлении чисел, таких как 123. Это было слишком узким, и, когда я углубляюсь в Regex, я вижу, что вам действительно нужно что-то определить. Поэтому я попросил экспоненциальную нотацию и получил ответ в this post: /^keyword\s+(-?(?:\d+|\d*\.\d*)(?:[Ee]-?(?:\d+|\d*\.\d*))?)/. Я пытался понять это, но до сих пор не смог.Соответствие всем номерам

Так что я прошу более конкретно. Мне нужно сопоставить цифры, здесь приводятся некоторые примеры:

13 
-999 
83.12300 
.151 
-.213 
1e14 
124e2 
-9e-4 

У вас есть это, обычная математическая штука.

И чтобы быть более конкретным, я даю вам свой код Perl для этого. Я ищу keyword на линии и вам нужно получить значение из этой строки. Я хотел бы получить это значение в одном Regex, потому что мой обходной путь с оператором or-|| вызывает проблемы.

my $value; 
open(FILE,"data.dat") or die "error on opening data: $!\n"; 
while (my $line = <FILE>) { 
     if (($line =~ /^keyword\s+(-?(?:\d+|\d*\.\d*)(?:[Ee]-?(?:\d+|\d*\.\d*))?)/x) || ($line =~ /^keyword\s*(\d*\.\d*)/)) { 
       $value = $1; 
     }; 
} 
close(FILE); 

Редактировать

Thx всем за подсказки до сих пор.

ответ

1

Существует еще один способ сделать это, и для этого вам не нужны регулярные выражения. Вы можете использовать looks_like_number от Scalar::Util

Вот пример: How do I tell if a variable has a numeric value in Perl? Я вставил его здесь для вас.


Пример:

#!/usr/local/bin/perl 

use warnings; 
use strict; 

use Scalar::Util qw(looks_like_number); 

my @exprs = qw(1 5.25 0.001 1.3e8 foo bar 1dd); 

foreach my $expr (@exprs) { 
    print "$expr is", looks_like_number($expr) ? '' : ' not', " a number\n"; 
} 

дает этот вывод:

1 is a number 
5.25 is a number 
0.001 is a number 
1.3e8 is a number 
foo is not a number 
bar is not a number 
1dd is not a number 

редактирования: @ комментарий Бородину

Вы могли бы использовать его таким образом, как это:

my $value; 
open(FILE,"data.dat") or die "error on opening data: $!\n"; 
while (my $line = <FILE>) { 
     if (($line =~ /^keyword +(.*)/)) { 
      my $number = $1; 
      if (looks_like_number($number)) { 
       $value = $number; 
      } 
     }; 
} 

редактировать: если вы должны иметь регулярное выражение, вы можете это выражение так:

#!/bin/perl 
use strict; 
use warnings; 

my @numbers = ('keyword 13', 
       ' word 25', 
       'keyword -999', 
       'keyword 83.12300', 
       'keyword .151', 
       'keyword -.213', 
       'keyword 1e14', 
       'keyword 124e2', 
       'keyword -9e-4 ', 
       ' keyword e43e', 
       'keyword 4.5.6', 
       'keyword 4..e', 
       'keyword NaN', 
       'keyword Inf'); 

for (@numbers) { 

     if (/^keyword +(-?((\d+\.?\d*)|(\d*\.?\d+))([Ee]-?\d+)?)/) { 

     print "$1 is a number\n"; 

    } else { 
     print "$_ does not match keyword or is not a number\n"; 
    } 

} 
+0

Это не выдержит число из середины строки, что, как представляется, требуется. – Borodin

+0

@borodin, см. Править. Я предполагаю, что моя точка зрения заключается в том, что нам не нужно делать регулярное выражение для соответствия числу, поскольку эта функциональность уже существует в ядре. – chilemagic

+0

Но теперь вы полагаетесь на число, являющееся * целым * остальной строки после слова «ключевое слово». Предположим, вы хотите найти числа в 'keyword 3.14 + .67 + 7e4'. Все 'look_like_number' будут делать это, задавая строку, сообщать вам, является ли * целая вещь * похожей на число. – Borodin

1

Второе регулярное выражение в вашем коде кажется избыточным, его можно безопасно удалить. Первое регулярное выражение должно соответствовать всем вашим тестовым таблицам. Есть ли что-то, с чем он не работает?

Вы также должны настроить свое регулярное выражение, поскольку в настоящее время он считает, что -.e-. является числом. Это происходит от \d*\.\d*, который соответствует .. Вы можете попробовать (?:\d+(?:\.\d*)?|\.\d+) вместо того, что у вас есть, что соответствовало бы 1) цифрам, 2) цифрам, за которыми следуют десятичные числа и, возможно, больше цифр, или 3) десятичная цифра с последующими цифрами.

+0

Thx Dan. Первое регулярное выражение (in или-statement) работает для обозначения exp. Но это не работает, например. '12.124'. Поэтому я попытался добавить второе регулярное выражение, которое работает для этого числа, если я использую его в одиночку. Но в or-statement он не работает. – EverythingRightPlace

+0

@ bashophil: Вы очень растерялись. Ваше первое регулярное выражение соответствует «12.124» просто отлично, за исключением «ключевого слова» в начале, которое вы таинственно не смогли объяснить. – Borodin

+0

@Borodin Пожалуйста, прочитайте мое сообщение. Я ищу ключевое слово и пытаюсь получить номер (независимо от того, какой формат) из этой строки. – EverythingRightPlace

2

Перейдите в cpan и получите Regexp::Common.

Используйте его как этот

use Regexp::Common; 

my $re = $RE{num}{real}; 

if ($line =~ /^keyword\s+($re)/) { 
    $value = $1; 
} 

Намного проще, чем сделай сам регулярное выражение качению.

+0

Также thx для этого намека, но я действительно хочу это понять. Regex кажется экстремально мощным, просто нужно завести свой мозг за него – EverythingRightPlace

+0

@Borodin Thx за ваше мнение, но вы можете убедить меня, что я что-то прочитал. Ofc. Я не так переживаю, как другие ... У меня есть пример из учебника, в котором говорится: '/ \ d \ d: \ d \ d /', который должен иметь что-то вроде '12: 15'.Просто чтобы показать мое предположение с двоеточием. Извините, что у меня не было времени, чтобы прочитать часы и часы учебников, я планирую это позже. Но у меня есть конкретная проблема и пытаюсь решить эту проблему. Спасибо. – EverythingRightPlace

+1

@ bashophil: На данный момент вы должны решить свою «конкретную проблему» *, приняв консультацию xcramps и используя «Regexp :: Common». Я улучшил его ответ, чтобы включить образец кода. – Borodin

0

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

#!/usr/bin/perl 

use strict; 
use warnings; 

my @numbers=(
"keyword 152;", 
"keyword 12.23;", 
"keyword -2.001;", 
"keyword .123;", 
"keyword -12.;", 
"keyword 55.44.33;", 
"keyword 3e14;", 
"keyword -3.000e0014;", 
"keyword 5e-04;", 
" keyword  5e-04; ", 
"keyword 5e-04 ;", 
"keyword .1e2;", 
"keyword 9.e3;", 
"keyword -0.01E-03;", 
"keyword 1.3e-03;", 
"keyword 1dd;", 
"keyword -12E3e1;", 
"keyword -.e.;", 
"keyword -.e-.;"); 

for (@numbers) { 

if ( /\s* keyword \s+  # stuff before matched number 
    (-?   # optional minus sign 
     (?:   # no saving of group in brackets 
     (?:\d+\.?\d*)  # match trailing digit and possible floating point number 
     |   # or 
     (?:\.\d+)  # no trailing digit and forced fpn 
    ) 
    (?:[Ee]-?\d+)?  # optional exponential notation 
    )   # end of group to be matched 
    ;\s*   # stuff after matched number 
    /x) { 

print "<<__$_\__>>\n\t $1 \n"; 
} else { 
print "<<__$_\__>>\n\t !!!!! no matching here !!!!!\n"; 
} 
} 

Выход:

<<__keyword 152;__>> 
    152 
<<__keyword 12.23;__>> 
    12.23 
<<__keyword -2.001;__>> 
    -2.001 
<<__keyword .123;__>> 
    .123 
<<__keyword -12.;__>> 
    -12. 
<<__keyword 55.44.33;__>> 
    !!!!! no matching here !!!!! 
<<__keyword 3e14;__>> 
    3e14 
<<__keyword -3.000e0014;__>> 
    -3.000e0014 
<<__keyword 5e-04;__>> 
    5e-04 
<<__ keyword  5e-04; __>> 
    5e-04 
<<__keyword 5e-04 ;__>> 
    !!!!! no matching here !!!!! 
<<__keyword .1e2;__>> 
    .1e2 
<<__keyword 9.e3;__>> 
    9.e3 
<<__keyword -0.01E-03;__>> 
    -0.01E-03 
<<__keyword 1.3e-03;__>> 
    1.3e-03 
<<__keyword 1dd;__>> 
    !!!!! no matching here !!!!! 
<<__keyword -12E3e1;__>> 
    !!!!! no matching here !!!!! 
<<__keyword -.e.;__>> 
    !!!!! no matching here !!!!! 
<<__keyword -.e-.;__>> 
    !!!!! no matching here !!!!! 

PS: Я прочитал, что ?: не может спасти RESSOURCES пока код работает, и это делает регулярное выражение не очень глаз людей, так что можно было бы оставить на это ,

Смежные вопросы