Search code examples
pythonregexunicodecyrillic

Regular expression works when tested with online tools, but does not work when executed in command line


I am using Python 2.7.10 Operational system Ubuntu 15.04

My goal: find all matches for a regular expression in a given string.

My problem: designed by me regular expression does not match the intended words, but matches the words it is not intended to match.

What is special about this case: I tested my regular expression in question with a few online regex testing applications (https://regex101.com/#python AND http://pythex.org/) and my regular expression does works well matching only those words I need and not matching those words I do not need. However, it works completely wrong when it comes to executing it in the command line.

Please help me to figure out the following: - why it works well while being tested online and does not works in command line? - how to improve my regex so that it works as intended?

Here is the code:

yuliaPattern = u'[Юю]л((ь(к\S*|ч\S*))|([яеию]\S*))+'
yuliaCompiled = re.compile(yuliaPattern, re.I)]
match = re_pattern.findall(text)

the resulting match is:

(u'\u044f\xbb,', u'', u'', u'\u044f\xbb,')

or in other terms:

я»,   я»,

Even without knowing Russian its clear that Юля is something very different from "я, "я and white-spaces.

The intended result: Actually there should not be any matches at all in this text.

The regular expression is: u'[Юю]л((ь(к\S*|ч\S*))|([яеию]\S*))+' It is intended to match the words deriving from: Юля, Юлия, Юльчин, Юлька case insensitive

The text is: Новости 15-00<br><br>1. Олланд пригрозил войной случае неуспеха переговоров Украине<br><br>В субботу французский лидер выступил мюнхенской конференции безопасности. Комментируя ситуацию Украине дипломатические усилия Парижа Берлина разрешению конфликта Донбассе, Олланд заявил, переговоры являются «одним последних шансов» достижения регионе. случае, долговременного решения кризиса будет, случится «известный сценарий – называется войной», заявил политик.<br><br>Читать далее: <br><br>2. Силовики нанесли 14 артиллерийских ракетных ударов территории ЛНР<br><br>Обстрелам подверглись населенные пункты Первомайск, Санжаровка, Красный Лиман, Обозное, Стаханов, Кировск, Райовка, район базы отдыха «Десюля», автомобильный мост трассе «Луганск — Станица Луганская» районе памятника князю Игорю. Зафиксировано применение крупнокалиберной ствольной артиллерии реактивных систем залпового огня «Град» «Ураган».<br><br>Читать далее: br><br>3. Басурин: переговоров интенсивность обстрелов Донецка увеличилась<br><br>Басурин отметил, встречи Порошенко канцлером Германии Ангелой Меркель президентом Франции Франсуа Олландом интенсивность обстрелов Донецка увеличилась, результате мирные жители провели одну беспокойную ночь.<br>Он обратил внимание то, начинаются переговоры представителями официального Киева, сразу резко растет количество жертв. Поэтому Басурин уверен, бойцы ВСУ умышленно нагнетают обстановку из-за нежелания договариваться перемирии.<br><br>Читать далее:


Solution

  • There is actually a single match in that text you quote.

    Your regex is finding what it's made to find.
    You're just not looking at the whole match.
    Instead you're just looking at the capture groups.

    If you would format your expression you could see how it relates to the match.

    First thing you'll notice is that [Юю]л is outside any capture group, but
    is part of the whole match, group 0.

     [Юю] л
     (                             # (1 start)
          (                             # (2 start)
               ь
               ( к \S* | ч \S* )             # (3)
          )                             # (2 end)
       |  
          ( [яеию] \S* )                # (4)
     )+                            # (1 end)
    

    This is the actual match result (with tool) it finds:

     **  Grp 0 -  ( pos 700 , len 5 ) 
    юля»,  
     **  Grp 1 -  ( pos 702 , len 3 ) 
    я»,  
     **  Grp 2 -  NULL 
     **  Grp 3 -  NULL 
     **  Grp 4 -  ( pos 702 , len 3 ) 
    я»,  
    

    Here it is converted (with tool) to \u notation. Look familiar?

     **  Grp 0 -  ( pos 700 , len 5 ) 
    \u044E\u043B\u044F\u00BB,  
     **  Grp 1 -  ( pos 702 , len 3 ) 
    \u044F\u00BB,  
     **  Grp 2 -  NULL 
     **  Grp 3 -  NULL 
     **  Grp 4 -  ( pos 702 , len 3 ) 
    \u044F\u00BB,  
    

    Update

    Can you, please, also advise on how can I get only match group 0 as a result? – @OstapDidenko

     [Юю] л
     (?:
          ь
          [кч] \S* 
       |  
          [яеию] \S* 
     )+
    

    usage

    re.findall(r'[Юю]л(?:ь[кч]\S*|[яеию]\S*)+', text, re.I)
    
    # ['юля»,']