Jste zde

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

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.

Přidat komentář