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.