Match vs search u regulárních výrazů v C++ a Pythonu

Od Petr Zemek, 2015-12-16

V příspěvku se podíváme na rozdíl mezi operacemi match a search u regulárních výrazů v jazycích C++ a Python. Především si však ukážeme záludnost, ve které se operace match ve zmíněných jazycích liší. Velmi stručně se podíváme i na pár dalších jazyků.

C++

V C++ je od C++11 ve standardní knihovně podpora pro práci s regulárními výrazy. Mezi dvě základní funkce zde patří std::regex_match() a std::regex_search(). První zmíněná zjišťuje, zda zadaný regulární výraz matchuje celý vstup. Druhá naopak zjišťuje, zda matchuje některá podčást vstupu. Ukažme si to na příkladu:

std::regex_match("abcd",  std::regex("ab")) // false
std::regex_search("abcd", std::regex("ab")) // true

Pomocí speciálních znaků ^ a $ si lze u std::regex_search() vynutit, aby matchování začínalo na začátku vstupu a končilo na konci vstupu. Příklad:

std::regex_search("abcd", std::regex("bc"))     // true
std::regex_search("abcd", std::regex("^bc"))    // false
std::regex_search("abcd", std::regex("bc$"))    // false
std::regex_search("abcd", std::regex("cd$"))    // true
std::regex_search("abcd", std::regex("^abcd$")) // true

Použití těchto znaků je však u std::regex_match() zbytečné, protože std::regex_match() matchuje vždy celý vstup. Proto má následující kód stejné chování:

std::regex_match("ab", std::regex("ab"))   // true
std::regex_match("ab", std::regex("^ab$")) // stejné jako případ výše, ale zbytečné ^ a $

Když už nyní víme, jak to funguje v C++, tak pojďme na Python.

Python

V Pythonu se pro práci s regulárními výrazy používá standardní modul re. Mezi typicky používané funkce pak patří re.match() a re.search(). Druhá zmíněná funkce (re.search()) funguje stejně, jako v C++. U re.match() je ale rozdíl: v Pythonu se oproti C++ hledá match na začátku vstupu, nikoliv pro celý vstup:

# re.match(pattern, string)
 
re.match(r'ab', 'abcd') # True

Naproti tomu u C++ bychom dostali pravý opak:

std::regex_match("abcd", std::regex("ab")) // false

Pokud chcete matchovat celý vstup, tak je potřeba použít re.fullmatch():

re.fullmatch(r'ab', 'abcd') # False

Tato funkce je však bohužel dostupná až od verze 3.4. Proto oproti C++ v Pythonu dává smysl použít $ i u re.match():

re.match(r'ab$', 'abcd') # False

Někdy se doporučuje v Pythonu používat ^ a $ i v případech, kdy to z technického hlediska nemá smysl, aby se předešlo problémům z důvodu nedostatečného chápání těchto funkcí a oné zmiňované záludnosti:

re.match(r'^ab$', 'ab')

Technicky je to stejné, jako re.match(r'ab$', 'ab'), ale čitelnější.

Další jazyky

Možná by vás nyní zajímalo, jak je to u jiných jazyků. Pár jsem jich vybral.

PHP:

preg_match("/ab/", "abcd") // 1

Ruby:

/ab/.match('abcd') # <MatchData "ab"> (true)

JavaScript:

'abcd'.match(/ab/) // 'ab' (true)

Java:

"abcd".matches("ab") // false

Jak je vidět, chování match se různí. Je na to proto potřeba dávat pozor.

Obsah tohoto pole je soukromý a nebude veřejně zobrazen.

Filtrované HTML (využíváno)

  • Povolené HTML značky: <a href hreflang> <em> <strong> <cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <table>
  • Zvýraznění syntaxe kódu lze povolit přes následující značky: <code>, <blockcode>, <bash>, <c>, <cpp>, <haskell>, <html>, <java>, <javascript>, <latex>, <perl>, <php>, <python>, <ruby>, <rust>, <sql>, <text>, <vim>, <xml>, <yaml>.
  • Řádky a odstavce se zalomí automaticky.
  • Webové a e-mailové adresy jsou automaticky převedeny na odkazy.
CAPTCHA
8 + 1 =
Vyřešte tento jednoduchý matematický příklad a vložte výsledek. Např. pro 1+3 vložte 4.
Nějak se mi tady rozmohl spam, takže poprosím o ověření.