Сопоставление двух слов с несколькими символами между ними в регулярном выражении - PullRequest
0 голосов
/ 01 октября 2011

Я хочу выполнить сопоставление для строки, когда за abc не следует несколько символов (возможно, ни одного) и заканчивается .com.

Я пытался со следующим:

(?!abc).*\.com

или

(?!abc).*?\.com

или

(?<!abc).*\.com

или

(?<!abc).*?\.com

Но ничего из этого не сработало. Пожалуйста, помогите.

Большое спасибо!

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

Извините, если я не прояснил себя. Просто приведите несколько примеров. Я хочу, чтобы def.edu, abc.com, abce.com, eabc.com и abcAnYTHing.com не совпадали, в то время как a.com, b.com, ab.com, ae.com и т. Д. Совпадают.

Ответы [ 4 ]

4 голосов
/ 01 октября 2011

Из вашей формулировки неясно, хотите ли вы соответствовать строке, заканчивающейся на .com И НЕ содержащей abc до этого; или чтобы соответствовать строке, которая не имеет «abc, сопровождаемый символами, сопровождаемыми .com».

Это означает, что в первом случае "def.edu" НЕ совпадает (без «abc», но не заканчивается на «.com»), но во втором случае "def.edu" соответствует (потому что это не «abcSOMETHING.com» )


В первом случае вам нужно использовать отрицательный взгляд :

(?<!abc.+)\.com$
# Use .* instead of .+ if you want "abc.com" to fail as well

ВАЖНО : ваше исходное выражение с использованием оглядки назад - # 3 ((?<!abc).*\.com) - не сработало , потому что оглядка назад ТОЛЬКО смотрит назад немедленно предшествующий следующему сроку. Следовательно, «что-то после abc» должно быть включено в поиск вместе с abc - как это делает мой RegEx выше.

ПРОБЛЕМА : мой RegEx выше вероятного не будет работать с вашим конкретным механизмом RegEx, если он не поддерживает общие запросы с выражением переменной длины (например, тот, что выше) - что ТОЛЬКО .NET делает в наши дни (хорошее резюме того, что делает и не поддерживает то, что ищет в прошлом, в http://www.regular -expressions.info / lookaround.html ).

Если это действительно так, вам придется выполнить двойное совпадение: сначала проверьте .com; захватывать все перед этим; тогда отрицательное совпадение на abc. Я буду использовать синтаксис Perl, так как вы не указали язык:

if (/^(.*)\.com$/) {
    if ($1 !~ /abc/) { 
    # Or, you can just use a substring:
    # if (index($1, "abc") < 0) {
        # PROFIT!
    }
}

Во втором случае САМОЕ ПРОСТОЕ, что нужно сделать, это сделать оператор "не соответствует" - например, !~ в Perl (или отрицание результата совпадения, если ваш язык не поддерживает «не совпадает»). Пример использования псевдокода:

if (NOT string.match(/abc.+\.com$/)) ...

Обратите внимание, что вам не нужно использовать ". +" / ". *" При использовании негативного вида сзади;

0 голосов
/ 01 октября 2011

Вы хотите исключить строки, которые начинаются с abc? То есть с xyzabc.com все будет в порядке? Если это так, это регулярное выражение должно работать:

^(?!abc).+\.com$

Если вы хотите убедиться, что abc не появляется в любом месте , используйте это:

^(?:(?!abc).)+\.com$

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

0 голосов
/ 01 октября 2011

Это выглядит как XY Проблема .

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

Мое решение (на Python) демонстрирует, что регулярные выражения не обязательно являются лучшим подходом и что решение проблемы с использованием функциональности обработки строк вашего языка программирования может привести к более эффективному и более поддерживаемому решению.

#!/usr/bin/env python

import unittest

def is_valid_domain(domain):
    return domain.endswith('.com') and 'abc' not in domain

class TestIsValidDomain(unittest.TestCase):

    def test_edu_invalid(self):
        self.assertFalse(is_valid_domain('def.edu'))

    def test_abc_invalid(self):
        self.assertFalse(is_valid_domain('abc.com'))
        self.assertFalse(is_valid_domain('abce.com'))
        self.assertFalse(is_valid_domain('abcAnYTHing.com'))

    def test_dotcom_valid(self):
        self.assertTrue(is_valid_domain('a.com'))
        self.assertTrue(is_valid_domain('b.com'))
        self.assertTrue(is_valid_domain('ab.com'))
        self.assertTrue(is_valid_domain('ae.com'))

if __name__ == '__main__':
    unittest.main()

Смотрите, бегите !

Обновление

Даже в таком языке, как Perl, где регулярные выражения идиоматичны, нет смысла сводить всю вашу логику в одно регулярное выражение. Эту функцию гораздо проще поддерживать:

sub is_domain_valid {
    my $domain = shift;
    return $domain =~ /\.com$/ && $domain !~ /abc/;
}

(я не программист на Perl, , но он работает и дает желаемые результаты )

0 голосов
/ 01 октября 2011

Конденсация:

Sorry if I did not make myself clear. Just give some examples.
I want def.edu, abc.com, abce.com, eabc.com and
abcAnYTHing.com do not match,
while a.com, b.com, ab.com, ae.com etc. match.

Новое регулярное выражение после пересмотренных примеров OP:
/^(?:(?!abc.*\.com\$|^def\.edu\$).)+\.(?:com|edu)\$/s

use strict;
use warnings;


my @samples = qw/
 <newline>
   shouldn't_pass 
   def.edu  abc.com  abce.com eabc.com 
 <newline>
   should_pass.com
   a.com    b.com    ab.com   ae.com
   abc.edu  def.com  defa.edu
 /;

my $regex = qr
  /
    ^    # Begin string
      (?:  # Group    

          (?!              # Lookahead ASSERTION
                abc.*\.com$     # At any character position, cannot have these in front of us.
              | ^def\.edu$      # (or 'def.*\.edu$')
           )               # End ASSERTION

           .               # This character passes

      )+   # End group, do 1 or more times

      \.   # End of string check,
      (?:com|edu)   # must be a '.com' or '.edu' (remove if not needed)

    $    # End string
  /sx;


print "\nmatch using   /^(?:(?!abc.*\.com\$|^def\.edu\$).)+\.(?:com|edu)\$/s \n";

for  my $str ( @samples )
{
   if ( $str =~ /<newline>/ ) {
      print "\n"; next;
   }

   if ( $str =~ /$regex/ ) {
       printf ("passed - $str\n");
   }
   else {
       printf ("failed - $str\n");
   }
}

Выход:

совпадение с использованием /^(?:(?!abc.*.com$|^def.edu$).)+.(?:com|edu)$/ s

не удалось - не должен проходить
не удалось - def.edu
не удалось - abc.com
не удалось - abce.com
не удалось - eabc.com

пройдено - should_pass.com
прошло - a.com
прошло - b.com
прошло - ab.com
прошло - ae.com
прошло - abc.edu
прошло - def.com
прошло - defa.edu

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...