Как мне сопоставить слово, за которым следует новая строка, а затем захватить следующую строку до новой строки?

Я редактирую кучу файлов SQL, и мне нужно удалить ссылки на дату в запросах. Однако способ написания файлов заключается в том, что логические операторы, такие как ИЛИ и И, находятся в отдельных строках, а остальная часть связанного аргумента находится в другой строке. Вот так:

OR
   field.lastupdate > DATE_SUB(CURDATE(), INTERVAL 31 DAY))
AND
  *some more code*

Я хочу удалить ИЛИ (и это может быть и И) до символа новой строки, в этом примере после второй скобки. Однако я хочу оставить остальную часть кода нетронутой.

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

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

Вот более полный пример, который, я надеюсь, прояснит ситуацию:

OR
        x.is_deleted = 0
OR
        x.lastupd > DATE_SUB(CURDATE(), INTERVAL 31 DAY))
AND
        (j.active = 1
OR
        j.is_deleted = 0
OR
        j.lastupd > DATE_SUB(CURDATE(), INTERVAL 31 DAY));

Итак, вы видите, что я хочу сохранить первое «ИЛИ» и следующую строку,

удалите второе «ИЛИ» и следующую за ним строку.

Сохраните «И» и строку, следующую за ней, а также следующую «ИЛИ» и соответствующую строку.

А затем удалите последнюю «ИЛИ» и ее строку, оставив последнюю «;».


person phileas fogg    schedule 22.07.2011    source источник
comment
[...] до символа новой строки, в этом примере после второй скобки новой строки после второй скобки нет. Вы просто хотите удалить следующую строку?   -  person Qtax    schedule 23.07.2011


Ответы (3)


$sql =~ s/\b(?:OR|AND)[ \t]*[\n\r]+(?=.*DATE).*(?<![;\s])//mg;

Удаляет OR (или AND) и содержимое следующей строки (если она содержит DATE), за исключением возможного окончания ;.

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

Пример на http://ideone.com/0Lbxp

person Qtax    schedule 23.07.2011

Ну, я не знаю, есть ли только одно предложение после предложения с ИЛИ/И.

Идея состоит в том, чтобы отслеживать флаг, который сообщит вам, что вы столкнулись с ИЛИ/И в предыдущем предложении.

Вероятно, вы можете сделать что-то вроде этого.

open(FPTR, "infilename")
    or die "\nCan't open $filename for reading: $!\n";
open(OUT, ">outfilename")
    or die "\nCan't open $OUT for writing: $!\n";
my $st=0;
while(<FPTR>)
{
if($_ =~ m/OR$/ || $_ =~ m/AND$/) {
    $st=1;
}
elsif($st==1 $$ **match to your sentence**) {
    $st=0; 
    next;#since you want to remove the line followed by line containing OR/AND

}
else {
    print OUT $_;
    #i'm not sure if here also you need to set $st=0;
}

}

close(FPTR);
close(OUT);
person A. K.    schedule 22.07.2011

Иногда простые решения являются лучшими. Этот сценарий будет (повторно) печатать только те строки, которые не соответствуют описанию строк, которые вы хотите удалить. Он напечатает завершающую точку с запятой ;, если найдет ее. Он сохранит строки как прочитанные.

Он основан на том, что ни одна строка не является пустой и что ни одна требуемая строка не содержит слово DATE_SUB.

Использование:

$ script.pl input.txt > output.txt

Код:

use strict;
use warnings;
use ARGV::readonly;

while (my $line1 = <>) {
    if ($line1 =~ /^\s*(OR|AND)\s*$/) {
        my $line2 = <>;
        if ($line2 =~ /DATE_SUB/) {
            if ($line2 =~ /;\s*$/) {
                print ";\n";
            }
        } else {
            print $line1, $line2;
        }
    } else {
        print $line1;
    }
}
person TLP    schedule 23.07.2011