в Perl, как найти подстроку, которая не соответствует шаблону - PullRequest
0 голосов
/ 14 июля 2010

Мне нужно найти дополнение этого:

$_ = 'aaaaabaaabaaabacaaaa';

while( /([a][a][a][a])/gc){
    next if pos()%4 != 0;
    my $b_pos = (pos()/4)-1;
    print " aaaa at :$b_pos\n";
}

То есть набор из 4 символов, который не является «аааа».
Следующее не работает

$_ = 'aaaaabaaabaaabacaaaa';

while( /([^a][^a][^a][^a])/gc){
    my $b_pos = (pos()/4)-1;
    print "not a at :$b_pos\n";
}

Конечно, я могу сделать это

$_ = 'aaaaabaaabaaabacaaaa';

while( /(....)/gc){
    next if $1 eq 'aaaa';
    my $b_pos = (pos()/4)-1;
    print "$1 a at :$b_pos\n";
}

Разве нет более прямого пути?

Чтобы уточнить ожидаемый результат, мне нужно найти все 4-буквенные наборы, которые не являются «аааа», а также их положением.
1-й кодовый выход

 aaaa at :0
 aaaa at :4

2-й код должен вывести

not aaaa at :1
not aaaa at :2
not aaaa at :3

3-й вывод кода, это то, что я ищу

abaa at :1
abaa at :2
abac at :3

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

Мой третий код дает мне ожидаемый результат. Он читает строку из 4 букв в то время и обрабатывает те, которые не являются «аааа».
Я также выяснил, благодаря всем вашим предложениям, что мой первый код не работает должным образом, он должен пропустить, если pos ()% 4! = 0, что будет означать, что шаблон охватывает две группы из 4. Я исправил код.

Несмотря на все ожидания, от меня и других, следующее ничего не дает вообще

/[^a]{4}/

Мне, наверное, стоит придерживаться третьего кода.

Ответы [ 5 ]

4 голосов
/ 14 июля 2010
/(?!aaaa)/

Это отрицательный прогноз, который соответствует первой позиции, где шаблон aaaa не соответствует.

С другой стороны,

/[^a]{4}/

будет соответствовать 4 символам вместе, которые не a.

1 голос
/ 14 июля 2010

РЕДАКТИРОВАТЬ: После еще немного возни и думал, что я нашел правильное решение, я оставлю предыдущий ответ для справки ...

Кажется, /aaaa(?!aaaa)....|(?!aaaa)..../gc является дополнением / aaaa / для ваших целей:

$_ = 'aaaaabaaabaaabacaaaa';
while( /aaaa(?!aaaa)....|(?!aaaa)..../gc ){
    my $b_pos = (pos()/4)-1;
    print substr($_,$b_pos*4,4)." at :$b_pos\n";
}

Дает в результате:

abaa at :1
abaa at :2
abac at :3

Предыдущий ответ

Отрицательный взгляд не взаимодействует с итерацией «блока», даже при вводе небольших выборок:

use POSIX floor;
$_ = 'aaaaabaaabaaabacaaaa';
while( /(?!aaaa)..../gc ){
    my $b_pos = floor(pos()/4);
    print " !aaaa at :$b_pos str:".substr($_,$b_pos*4,4);
    print " c_pos:".(pos()-4)." str:".substr($_,(pos()-4),4)."\n";
}

С выводом:

 !aaaa at :1 str:abaa c_pos:2 str:aaab
 !aaaa at :2 str:abaa c_pos:6 str:aaab
 !aaaa at :3 str:abac c_pos:10 str:aaab
 !aaaa at :4 str:aaaa c_pos:14 str:acaa

Это потому, что предвидение будет оцениваться символ за символом, а не в блоках по 4. Это означает, что в случае с aaaabaaa, он будет проверять aaaa, а затем aaab, который не будет совпадать с aaaa, таким образом, они будут использованы, а не baaa как можно было бы хотеть ...

Однако разумное использование map, grep и split решает проблему:

my $c = 0;
print "!aaaa at positions: ", 
      join ",", map { $$_[1] } 
                    grep { $$_[0] !~ /aaaa/ } 
                         map { [$_, $c++ ] } 
                             grep /./, split /(.{4})/, $_;
print "\n";

Результат:

!aaaa at positions: 1,2,3

Пояснение:

  1. split /(.width4goti)/, $ _ разделит ввод на список блоков из 4 символов
  2. Однако использование захвата регулярных выражений в split может привести к тому, что пустые блоки будут в списке, поэтому мы исключаем их, используя grep /./
  3. Теперь мы создадим кортежи входных данных плюс номер блока (таким образом, нам нужен $ c, инициализированный в 0 ...)
  4. Теперь мы фильтруем элементы, которые не соответствуют 'aaaa'
  5. Теперь мы сопоставляем, чтобы получить только номер блока ...

Для соответствия точному выводу:

my $c = 0; 
print "",  
  join "\n",  
       map { $$_[0]." at: ".$$_[1] }  
           grep { $$_[0] !~ /aaaa/ }  
                map { [$_, $c++ ] }  
                    grep /./, split /(.{4})/, $_; 
print "\n"; 
1 голос
/ 14 июля 2010
0 голосов
/ 14 июля 2010

Попробуйте это:

/(?:(?!aaaa)[a-z]){4}/g

Перед сопоставлением каждого символа опережающий взгляд гарантирует, что они не aaaa.

0 голосов
/ 14 июля 2010

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

/[^a]{4}/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...