2009-05-12 2 views
2

из этой строки, (champs1 (champs6 donnee_o donnee_f) [(champs2 [] (champs3 _YOJNJeyyyyyyB (champs4 donnee_x)) (debut 144825 25345) (fin 244102 40647)), (champs2 [] (champs3 _FuGNJeyyyyyyB (champs4 donnee_z)) (debut 796443 190570) (fin 145247 42663))] [] [])., я хотел бы извлечь первое число после слова «дебют» и первое число после слова «fin». Я пишу это:[Perl]: прочитайте каталог и файлы, а regex

while (my $readfile = <FILE>) #read each line and check the first value X1 after the word "coorDeb" and the first value X2 after the word "coorFin" 
{ 
    my ($line) = $_; 
    chomp ($line); 

    ($first, $second)= ~m/coorDeb/\s\S*\s\S*\s\S*\s\S*\s\S*; #CoorDeb first, following by X1 

    $X1=$first; $X4=$second; 
    $lenght1=$second-$first; # Calculation of the lenght of first segment 

    $line =~ m//coorFin/(\s*)\S*\s*\S*\s*\S*\s*\S*\s*(\S*/); #CoorFin first, following by X1 
    $lenght2=$second-$first; # Calculation of the lenght of first segment 

    push(@elements1, $lenght1); #Push the lenght into a table to compute the mean of lenght for the segment n°1 
    push(@elements2, $lenght2); #Push the lenght into a table to compute the mean of lenght for the segment n°2 
} 

Может ли кто-нибудь помочь мне с регулярным выражением, пожалуйста? Спасибо.

+0

@tongium, код был отредактирован, чтобы сделать его доступным для чтения. Пожалуйста, проверьте, что это все еще то, что вы хотели. @Nathan, я вернул ваше редактирование, так как code/pre заполняет символы <>, думая, что они HTML. – paxdiablo

+0

Пожалуйста, используйте оператор повторения {M, N} Например, (\ S * \ s *) {5} –

+0

@Pax, не проблема, но как насчет того, чтобы строка была максимально читаема? –

ответ

0

Если я правильно понял, вам просто нужно прочитать файл и найти два значения. Эти значения представляют собой ряд цифр после слова «плавник» и после слова «дебют». Прямо сейчас, вы пытаетесь сопоставить их, ища что-то, что происходит перед интересующей вас строкой. Возможно, вам стоит искать фактическую интересующую вас информацию.

В регулярном выражении почти всегда лучше искать интересный текст, а не пытаться пропускать не интересный текст. Что-то вроде следующего будет работать лучше.

Обратите внимание, что я изменил ваш файл на чтение, потому что вы читали переменную, а затем обрабатывали $ _, что (почти определенно) не то, что вы имели в виду.

while (my $line = <FILE>) #read each line from FILE. 
{ 
    chomp ($line); 

    # These two lines could be combined but this is a little clearer. 
    # Matching against [0-9] because \d matches all unicode digits. 
    my ($fin_digits) = $line =~ /fin\s+([0-9]+)/; 
    my ($debut_digits) = $line =~ /debut\s+([0-9]+)/; # as above. 

    # Continue processing below... 
} 

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

UPDATE

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

while (my $line = <FILE>) #read each line from FILE. 
{ 
    chomp ($line); 

    # These two lines could be combined but this is a little clearer. 
    # Matching against [0-9] because \d matches all unicode digits. 
    # In list context, m// returns the matches in order, the /g modifier 
    # makes this a global match - in a loop this means each pair of 
    # matches will be returned in order. 
    while (my ($debut, $fin) =~ /debut\s+([0-9]+).+?fin\s+([0-9]+)/g) 
    { 
      # result processing here. 
    } 


} 
4

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

#!/usr/bin/perl 

use strict; 
use warnings; 

my @elements; 
while (<DATA>) { 
    my $line = $_; 
    push @elements, $line =~ /debut (\d+).*?fin (\d+)/g; 
} 

print join ',', @elements; 
print "\n"; 
__DATA__ 
(champs1 (champs6 donnee_o donnee_f) [(champs2 [] (champs3 _YOJNJeyyyyyyB (champs4 donnee_x)) (debut 144825 25345) (fin 244102 40647)), (champs2 [] (champs3 _FuGNJeyyyyyyB (champs4 donnee_z)) (debut 796443 190570) (fin 145247 42663))] [] []) 

Этот код генерирует выходную

144825,244102,796443,145247 

($line это даже действительно не нужна, так как m// работает на $_ по умолчанию , но я оставил это там, если вам действительно нужно сделать другую обработку. И push @elements, /debut (\d+).*?fin (\d+)/g; немного более запутанный, чем я считаю уместным здесь.)

Если вы не обеспокоены остроумием ч согласующих пар, вы можете также использовать два отдельных массива и заменить push линию

push @debuts, $line =~ /debut (\d+)/g; 
push @fins, $line =~ /fin (\d+)/g; 
Смежные вопросы