ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ HOWTO¶
ਜਾਣ-ਪਛਾਣ¶
ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ (ਜਿਨ੍ਹਾਂ ਨੂੰ REs, regexes ਜਾਂ regex patterns ਵੀ ਕਿਹਾ ਜਾਂਦਾ ਹੈ) ਅਸਲ ਵਿੱਚ ਇੱਕ ਛੋਟੀ ਪਰ ਬਹੁਤ ਵਿਸ਼ੇਸ਼ ਪ੍ਰੋਗਰਾਮਿੰਗ ਭਾਸ਼ਾ ਹੁੰਦੀ ਹੈ ਜੋ Python ਦੇ ਅੰਦਰ ਸ਼ਾਮਲ ਹੈ ਅਤੇ re ਮੋਡੀਊਲ ਰਾਹੀਂ ਉਪਲਬਧ ਕਰਵਾਈ ਜਾਂਦੀ ਹੈ। ਇਸ ਛੋਟੀ ਭਾਸ਼ਾ ਦੀ ਮਦਦ ਨਾਲ ਤੁਸੀਂ ਉਹ ਨਿਯਮ ਨਿਰਧਾਰਤ ਕਰਦੇ ਹੋ ਜਿਨ੍ਹਾਂ ਨਾਲ ਉਹਨਾਂ ਸੰਭਾਵਿਤ ਸਟਰਿੰਗਾਂ ਦਾ ਸਮੂਹ ਤਿਆਰ ਹੁੰਦਾ ਹੈ ਜਿਨ੍ਹਾਂ ਨੂੰ ਤੁਸੀਂ ਮੈਚ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ। ਇਸ ਸਮੂਹ ਵਿੱਚ ਅੰਗਰੇਜ਼ੀ ਵਾਕ, ਈ-ਮੇਲ ਪਤੇ, TeX ਕਮਾਂਡਾਂ ਜਾਂ ਤੁਹਾਡੀ ਪਸੰਦ ਦੀ ਕੋਈ ਵੀ ਚੀਜ਼ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ। ਫਿਰ ਤੁਸੀਂ ਅਜਿਹੇ ਸਵਾਲ ਪੁੱਛ ਸਕਦੇ ਹੋ ਜਿਵੇਂ "ਕੀ ਇਹ ਸਟਰਿੰਗ ਇਸ ਪੈਟਰਨ ਨਾਲ ਮੈਚ ਕਰਦੀ ਹੈ?" ਜਾਂ "ਕੀ ਇਸ ਸਟਰਿੰਗ ਵਿੱਚ ਕਿਤੇ ਵੀ ਇਸ ਪੈਟਰਨ ਦਾ ਮੈਚ ਮੌਜੂਦ ਹੈ?"। ਤੁਸੀਂ REs ਦੀ ਵਰਤੋਂ ਸਟਰਿੰਗ ਨੂੰ ਸੋਧਣ ਜਾਂ ਉਸਨੂੰ ਵੱਖ-ਵੱਖ ਢੰਗਾਂ ਨਾਲ ਵੰਡਣ ਲਈ ਵੀ ਕਰ ਸਕਦੇ ਹੋ।
ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਪੈਟਰਨਾਂ ਨੂੰ bytecode ਦੀ ਇੱਕ ਲੜੀ ਵਿੱਚ compile ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਜਿਸਨੂੰ ਬਾਅਦ ਵਿੱਚ C ਵਿੱਚ ਲਿਖਿਆ ਗਿਆ matching engine ਚਲਾਉਂਦਾ ਹੈ। ਉੱਚ ਪੱਧਰੀ ਵਰਤੋਂ ਲਈ ਕਈ ਵਾਰ ਇਹ ਸਮਝਣਾ ਜ਼ਰੂਰੀ ਹੁੰਦਾ ਹੈ ਕਿ matching engine ਕਿਸੇ ਦਿੱਤੀ ਗਈ RE ਨੂੰ ਕਿਵੇਂ ਚਲਾਏਗਾ ਅਤੇ RE ਨੂੰ ਇਸ ਤਰੀਕੇ ਨਾਲ ਲਿਖਣਾ ਪੈਂਦਾ ਹੈ ਕਿ ਉਸ ਤੋਂ ਬਣਨ ਵਾਲਾ bytecode ਹੋਰ ਤੇਜ਼ੀ ਨਾਲ ਚੱਲੇ। Optimization ਬਾਰੇ ਇਸ ਦਸਤਾਵੇਜ਼ ਵਿੱਚ ਚਰਚਾ ਨਹੀਂ ਕੀਤੀ ਗਈ ਕਿਉਂਕਿ ਇਸ ਲਈ matching engine ਦੇ ਅੰਦਰੂਨੀ ਢਾਂਚੇ ਦੀ ਚੰਗੀ ਸਮਝ ਲੋੜੀਂਦੀ ਹੈ।
ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਭਾਸ਼ਾ ਕਾਫ਼ੀ ਛੋਟੀ ਅਤੇ ਸੀਮਿਤ ਹੈ, ਇਸ ਲਈ ਹਰ ਕਿਸਮ ਦਾ ਸਟਰਿੰਗ ਪ੍ਰੋਸੈਸਿੰਗ ਕੰਮ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਨਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਕੁਝ ਅਜਿਹੇ ਕੰਮ ਵੀ ਹਨ ਜੋ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਨਾਲ ਕੀਤੇ ਤਾਂ ਜਾ ਸਕਦੇ ਹਨ, ਪਰ ਉਨ੍ਹਾਂ ਦੀਆਂ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਬਹੁਤ ਹੀ ਜਟਿਲ ਬਣ ਜਾਂਦੀਆਂ ਹਨ। ਅਜਿਹੀਆਂ ਸਥਿਤੀਆਂ ਵਿੱਚ ਪ੍ਰੋਸੈਸਿੰਗ ਲਈ ਸਿੱਧਾ Python ਕੋਡ ਲਿਖਣਾ ਵਧੀਆ ਹੋ ਸਕਦਾ ਹੈ; ਭਾਵੇਂ Python ਕੋਡ ਇੱਕ ਜਟਿਲ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਨਾਲੋਂ ਹੌਲਾ ਹੋਵੇ, ਪਰ ਉਹ ਆਮ ਤੌਰ 'ਤੇ ਸਮਝਣ ਵਿੱਚ ਕਾਫ਼ੀ ਆਸਾਨ ਹੁੰਦਾ ਹੈ।
ਸਧਾਰਣ ਪੈਟਰਨ¶
ਅਸੀਂ ਸਭ ਤੋਂ ਸਧਾਰਣ ਸੰਭਵ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਬਾਰੇ ਸਿੱਖਣ ਨਾਲ ਸ਼ੁਰੂ ਕਰਾਂਗੇ। ਕਿਉਂਕਿ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਦੀ ਵਰਤੋਂ ਸਟਰਿੰਗਾਂ ਉੱਤੇ ਕਾਰਵਾਈ ਕਰਨ ਲਈ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਇਸ ਲਈ ਅਸੀਂ ਸਭ ਤੋਂ ਆਮ ਕੰਮ ਨਾਲ ਸ਼ੁਰੂ ਕਰਾਂਗੇ: ਅੱਖਰਾਂ ਨੂੰ ਮੈਚ ਕਰਨਾ।
ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਦੇ ਪਿੱਛੇ ਮੌਜੂਦ ਕੰਪਿਊਟਰ ਸਾਇੰਸ ਦੇ ਸਿਧਾਂਤਾਂ (deterministic ਅਤੇ non-deterministic finite automata) ਦੀ ਵਿਸਤ੍ਰਿਤ ਵਿਆਖਿਆ ਲਈ ਤੁਸੀਂ ਕੰਪਾਇਲਰ ਲਿਖਣ ਬਾਰੇ ਲਗਭਗ ਕਿਸੇ ਵੀ ਪਾਠ ਪੁਸਤਕ ਨੂੰ ਵੇਖ ਸਕਦੇ ਹੋ।
ਅੱਖਰਾਂ ਦਾ ਮੈਚ ਕਰਨਾ¶
ਜ਼ਿਆਦਾਤਰ ਅੱਖਰ ਅਤੇ ਚਿੰਨ੍ਹ ਆਪਣੇ ਆਪ ਨਾਲ ਹੀ ਮੈਚ ਕਰਦੇ ਹਨ। ਉਦਾਹਰਨ ਵਜੋਂ, ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ test ਸਟਰਿੰਗ test ਨਾਲ ਬਿਲਕੁਲ ਸਹੀ ਮੈਚ ਕਰੇਗੀ। (ਤੁਸੀਂ case-insensitive mode ਵੀ ਚਾਲੂ ਕਰ ਸਕਦੇ ਹੋ ਜਿਸ ਨਾਲ ਇਹ RE Test ਜਾਂ TEST ਨਾਲ ਵੀ ਮੈਚ ਕਰ ਸਕੇਗੀ; ਇਸ ਬਾਰੇ ਅੱਗੇ ਹੋਰ ਜਾਣਕਾਰੀ ਦਿੱਤੀ ਗਈ ਹੈ।)
ਇਸ ਨਿਯਮ ਦੇ ਕੁਝ ਅਪਵਾਦ ਹਨ; ਕੁਝ ਅੱਖਰ ਖਾਸ metacharacters ਹੁੰਦੇ ਹਨ ਅਤੇ ਆਪਣੇ ਆਪ ਨਾਲ ਮੈਚ ਨਹੀਂ ਕਰਦੇ। ਇਸ ਦੀ ਬਜਾਏ, ਇਹ ਸੰਕੇਤ ਦਿੰਦੇ ਹਨ ਕਿ ਕੋਈ ਵਿਸ਼ੇਸ਼ ਚੀਜ਼ ਮੈਚ ਕੀਤੀ ਜਾਣੀ ਚਾਹੀਦੀ ਹੈ ਜਾਂ ਇਹ RE ਦੇ ਹੋਰ ਭਾਗਾਂ ਨੂੰ ਦੁਹਰਾਉਣ ਜਾਂ ਉਨ੍ਹਾਂ ਦਾ ਅਰਥ ਬਦਲਣ ਦਾ ਕੰਮ ਕਰਦੇ ਹਨ। ਇਸ ਦਸਤਾਵੇਜ਼ ਦਾ ਵੱਡਾ ਹਿੱਸਾ ਵੱਖ-ਵੱਖ metacharacters ਅਤੇ ਉਨ੍ਹਾਂ ਦੇ ਉਪਯੋਗ ਬਾਰੇ ਚਰਚਾ ਕਰਨ ਲਈ ਸਮਰਪਿਤ ਹੈ।
ਇੱਥੇ metacharacters ਦੀ ਪੂਰੀ ਸੂਚੀ ਦਿੱਤੀ ਗਈ ਹੈ; ਉਨ੍ਹਾਂ ਦੇ ਅਰਥਾਂ ਬਾਰੇ ਇਸ HOWTO ਦੇ ਬਾਕੀ ਹਿੱਸੇ ਵਿੱਚ ਚਰਚਾ ਕੀਤੀ ਜਾਵੇਗੀ।
. ^ $ * + ? { } [ ] \ | ( )
ਪਹਿਲੇ metacharacters ਜਿਨ੍ਹਾਂ ਬਾਰੇ ਅਸੀਂ ਗੱਲ ਕਰਾਂਗੇ ਉਹ [ ਅਤੇ ] ਹਨ। ਇਹ character class ਨਿਰਧਾਰਤ ਕਰਨ ਲਈ ਵਰਤੇ ਜਾਂਦੇ ਹਨ, ਜੋ ਅੱਖਰਾਂ ਦਾ ਇੱਕ ਸਮੂਹ ਹੁੰਦਾ ਹੈ ਜਿਸਨੂੰ ਤੁਸੀਂ ਮੈਚ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ। ਅੱਖਰਾਂ ਨੂੰ ਵੱਖ-ਵੱਖ ਤੌਰ 'ਤੇ ਲਿਖਿਆ ਜਾ ਸਕਦਾ ਹੈ ਜਾਂ ਦੋ ਅੱਖਰਾਂ ਦੇ ਵਿਚਕਾਰ '-' ਲਗਾ ਕੇ ਇੱਕ range ਦਰਸਾਈ ਜਾ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, [abc] ਕਿਸੇ ਵੀ a, b ਜਾਂ c ਅੱਖਰ ਨਾਲ ਮੈਚ ਕਰੇਗਾ; ਇਹ [a-c] ਦੇ ਬਰਾਬਰ ਹੈ ਜੋ ਉਸੇ ਸਮੂਹ ਨੂੰ range ਦੀ ਮਦਦ ਨਾਲ ਦਰਸਾਉਂਦਾ ਹੈ। ਜੇ ਤੁਸੀਂ ਸਿਰਫ਼ ਛੋਟੇ ਅੱਖਰਾਂ ਨਾਲ ਮੈਚ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡੀ RE [a-z] ਹੋਵੇਗੀ।
Metacharacters (\ ਤੋਂ ਇਲਾਵਾ) classes ਦੇ ਅੰਦਰ ਸਰਗਰਮ ਨਹੀਂ ਹੁੰਦੇ। ਉਦਾਹਰਨ ਲਈ, [akm$] ਕਿਸੇ ਵੀ 'a', 'k', 'm' ਜਾਂ '$' ਅੱਖਰ ਨਾਲ ਮੈਚ ਕਰੇਗਾ; '$' ਆਮ ਤੌਰ 'ਤੇ ਇੱਕ metacharacter ਹੁੰਦਾ ਹੈ, ਪਰ character class ਦੇ ਅੰਦਰ ਇਹ ਆਪਣੀ ਖਾਸ ਵਿਸ਼ੇਸ਼ਤਾ ਗੁਆ ਬੈਠਦਾ ਹੈ।
ਤੁਸੀਂ class ਦੇ ਅੰਦਰ ਦਰਸਾਏ ਨਾ ਗਏ ਅੱਖਰਾਂ ਨਾਲ ਮੈਚ ਕਰਨ ਲਈ ਉਸ ਸਮੂਹ ਦਾ complement ਬਣਾ ਸਕਦੇ ਹੋ। ਇਹ class ਦੇ ਪਹਿਲੇ ਅੱਖਰ ਵਜੋਂ '^' ਲਗਾ ਕੇ ਦਰਸਾਇਆ ਜਾਂਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, [^5] ਹਰ ਉਸ ਅੱਖਰ ਨਾਲ ਮੈਚ ਕਰੇਗਾ ਜੋ '5' ਨਹੀਂ ਹੈ। ਜੇ caret character class ਦੇ ਕਿਸੇ ਹੋਰ ਸਥਾਨ 'ਤੇ ਆਵੇ, ਤਾਂ ਇਸਦਾ ਕੋਈ ਖਾਸ ਅਰਥ ਨਹੀਂ ਹੁੰਦਾ। ਉਦਾਹਰਨ ਲਈ: [5^] ਜਾਂ ਤਾਂ '5' ਜਾਂ '^' ਨਾਲ ਮੈਚ ਕਰੇਗਾ।
ਸ਼ਾਇਦ ਸਭ ਤੋਂ ਮਹੱਤਵਪੂਰਨ metacharacter backslash \ ਹੈ। Python string literals ਵਾਂਗ, backslash ਤੋਂ ਬਾਅਦ ਵੱਖ-ਵੱਖ ਅੱਖਰ ਲਗਾ ਕੇ ਖਾਸ sequences ਦਰਸਾਈਆਂ ਜਾ ਸਕਦੀਆਂ ਹਨ। ਇਹ ਸਾਰੇ metacharacters ਨੂੰ escape ਕਰਨ ਲਈ ਵੀ ਵਰਤੀ ਜਾਂਦੀ ਹੈ ਤਾਂ ਜੋ ਤੁਸੀਂ ਪੈਟਰਨ ਵਿੱਚ ਉਨ੍ਹਾਂ ਨਾਲ ਸਿੱਧਾ ਮੈਚ ਕਰ ਸਕੋ; ਉਦਾਹਰਨ ਲਈ, ਜੇ ਤੁਹਾਨੂੰ [ ਜਾਂ \ ਨਾਲ ਮੈਚ ਕਰਨਾ ਹੋਵੇ, ਤਾਂ ਤੁਸੀਂ ਉਨ੍ਹਾਂ ਤੋਂ ਪਹਿਲਾਂ backslash ਲਗਾ ਕੇ ਉਨ੍ਹਾਂ ਦਾ ਖਾਸ ਅਰਥ ਹਟਾ ਸਕਦੇ ਹੋ: \[ ਜਾਂ \\।
'\' ਨਾਲ ਸ਼ੁਰੂ ਹੋਣ ਵਾਲੀਆਂ ਕੁਝ ਖਾਸ sequences ਪਹਿਲਾਂ ਤੋਂ ਪਰਿਭਾਸ਼ਿਤ ਅੱਖਰ ਸਮੂਹਾਂ ਨੂੰ ਦਰਸਾਉਂਦੀਆਂ ਹਨ ਜੋ ਅਕਸਰ ਲਾਭਦਾਇਕ ਹੁੰਦੀਆਂ ਹਨ, ਜਿਵੇਂ ਅੰਕਾਂ ਦਾ ਸਮੂਹ, ਅੱਖਰਾਂ ਦਾ ਸਮੂਹ ਜਾਂ ਉਹ ਸਭ ਕੁਝ ਜੋ whitespace ਨਹੀਂ ਹੈ।
ਆਓ ਇੱਕ ਉਦਾਹਰਨ ਵੇਖੀਏ: \w ਕਿਸੇ ਵੀ ਅੱਖਰ-ਅੰਕ ਅੱਖਰ ਨਾਲ ਮੈਚ ਕਰਦਾ ਹੈ। ਜੇ regex pattern ਨੂੰ bytes ਦੇ ਰੂਪ ਵਿੱਚ ਦਰਸਾਇਆ ਗਿਆ ਹੋਵੇ, ਤਾਂ ਇਹ class [a-zA-Z0-9_] ਦੇ ਬਰਾਬਰ ਹੁੰਦਾ ਹੈ। ਜੇ regex pattern ਇੱਕ string ਹੋਵੇ, ਤਾਂ \w unicodedata ਮੋਡੀਊਲ ਦੁਆਰਾ ਪ੍ਰਦਾਨ ਕੀਤੇ Unicode ਡਾਟਾਬੇਸ ਵਿੱਚ ਅੱਖਰ ਵਜੋਂ ਚਿੰਨ੍ਹਿਤ ਸਾਰੇ ਅੱਖਰਾਂ ਨਾਲ ਮੈਚ ਕਰੇਗਾ। ਤੁਸੀਂ regular expression compile ਕਰਦੇ ਸਮੇਂ re.ASCII flag ਦੇ ਕੇ string pattern ਵਿੱਚ \w ਦੀ ਹੋਰ ਸੀਮਿਤ ਪਰਿਭਾਸ਼ਾ ਵਰਤ ਸਕਦੇ ਹੋ।
ਹੇਠਾਂ ਦਿੱਤੀ special sequences ਦੀ ਸੂਚੀ ਪੂਰੀ ਨਹੀਂ ਹੈ। Unicode string patterns ਲਈ sequences ਦੀ ਪੂਰੀ ਸੂਚੀ ਅਤੇ ਵਿਸਤ੍ਰਿਤ class definitions ਲਈ Standard Library reference ਵਿੱਚ Regular Expression Syntax ਦਾ ਆਖਰੀ ਭਾਗ ਵੇਖੋ। ਆਮ ਤੌਰ 'ਤੇ Unicode ਸੰਸਕਰਣ Unicode ਡਾਟਾਬੇਸ ਦੀ ਉਚਿਤ ਸ਼੍ਰੇਣੀ ਵਿੱਚ ਆਉਣ ਵਾਲੇ ਹਰ ਅੱਖਰ ਨਾਲ ਮੈਚ ਕਰਦੇ ਹਨ।
\dਕਿਸੇ ਵੀ ਦਸ਼ਮਲਵ ਅੰਕ ਨਾਲ ਮੈਚ ਕਰਦਾ ਹੈ; ਇਹ class
[0-9]ਦੇ ਬਰਾਬਰ ਹੈ।\Dਕਿਸੇ ਵੀ ਗੈਰ-ਅੰਕੀ ਅੱਖਰ ਨਾਲ ਮੈਚ ਕਰਦਾ ਹੈ; ਇਹ class
[^0-9]ਦੇ ਬਰਾਬਰ ਹੈ।\sਕਿਸੇ ਵੀ whitespace ਅੱਖਰ ਨਾਲ ਮੈਚ ਕਰਦਾ ਹੈ; ਇਹ class
[ \t\n\r\f\v]ਦੇ ਬਰਾਬਰ ਹੈ।\Sਕਿਸੇ ਵੀ non-whitespace ਅੱਖਰ ਨਾਲ ਮੈਚ ਕਰਦਾ ਹੈ; ਇਹ class
[^ \t\n\r\f\v]ਦੇ ਬਰਾਬਰ ਹੈ।\wਕਿਸੇ ਵੀ ਅੱਖਰ-ਅੰਕ ਅੱਖਰ ਨਾਲ ਮੈਚ ਕਰਦਾ ਹੈ; ਇਹ class
[a-zA-Z0-9_]ਦੇ ਬਰਾਬਰ ਹੈ।\Wਕਿਸੇ ਵੀ ਗੈਰ-ਅੱਖਰ-ਅੰਕ ਅੱਖਰ ਨਾਲ ਮੈਚ ਕਰਦਾ ਹੈ; ਇਹ class
[^a-zA-Z0-9_]ਦੇ ਬਰਾਬਰ ਹੈ।
ਇਨ੍ਹਾਂ sequences ਨੂੰ character class ਦੇ ਅੰਦਰ ਵੀ ਸ਼ਾਮਲ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, [\s,.] ਇੱਕ character class ਹੈ ਜੋ ਕਿਸੇ ਵੀ whitespace ਅੱਖਰ, ',' ਜਾਂ '.' ਨਾਲ ਮੈਚ ਕਰੇਗੀ।
ਇਸ ਭਾਗ ਦਾ ਆਖਰੀ metacharacter . ਹੈ। ਇਹ newline character ਤੋਂ ਇਲਾਵਾ ਹਰ ਚੀਜ਼ ਨਾਲ ਮੈਚ ਕਰਦਾ ਹੈ, ਅਤੇ ਇੱਕ ਵਿਕਲਪਕ mode (re.DOTALL) ਵਿੱਚ ਇਹ newline ਨਾਲ ਵੀ ਮੈਚ ਕਰਦਾ ਹੈ। . ਅਕਸਰ ਉਸ ਵੇਲੇ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ ਜਦੋਂ ਤੁਸੀਂ "ਕਿਸੇ ਵੀ ਅੱਖਰ" ਨਾਲ ਮੈਚ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ।
ਚੀਜ਼ਾਂ ਨੂੰ ਦੁਹਰਾਉਣਾ¶
ਵੱਖ-ਵੱਖ ਅੱਖਰ ਸਮੂਹਾਂ ਨਾਲ ਮੈਚ ਕਰਨ ਦੀ ਸਮਰੱਥਾ ਉਹ ਪਹਿਲੀ ਚੀਜ਼ ਹੈ ਜੋ regular expressions ਕਰ ਸਕਦੀਆਂ ਹਨ ਅਤੇ ਜੋ strings ਉੱਤੇ ਉਪਲਬਧ methods ਨਾਲ ਪਹਿਲਾਂ ਹੀ ਸੰਭਵ ਨਹੀਂ ਸੀ। ਹਾਲਾਂਕਿ, ਜੇ regexes ਦੀ ਇਹੀ ਇਕੋ ਵਾਧੂ ਸਮਰੱਥਾ ਹੁੰਦੀ, ਤਾਂ ਇਹ ਕੋਈ ਵੱਡੀ ਤਰੱਕੀ ਨਾ ਹੁੰਦੀ। ਇੱਕ ਹੋਰ ਮਹੱਤਵਪੂਰਨ ਸਮਰੱਥਾ ਇਹ ਹੈ ਕਿ ਤੁਸੀਂ ਨਿਰਧਾਰਤ ਕਰ ਸਕਦੇ ਹੋ ਕਿ RE ਦੇ ਕੁਝ ਹਿੱਸਿਆਂ ਨੂੰ ਕਿੰਨੀ ਵਾਰ ਦੁਹਰਾਇਆ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ।
ਦੁਹਰਾਉਣ ਲਈ ਪਹਿਲਾ metacharacter ਜਿਸ ਬਾਰੇ ਅਸੀਂ ਗੱਲ ਕਰਾਂਗੇ ਉਹ * ਹੈ। * ਅਸਲ '*' ਅੱਖਰ ਨਾਲ ਮੈਚ ਨਹੀਂ ਕਰਦਾ; ਇਸ ਦੀ ਬਜਾਏ, ਇਹ ਦਰਸਾਉਂਦਾ ਹੈ ਕਿ ਪਿਛਲਾ ਅੱਖਰ ਬਿਲਕੁਲ ਇੱਕ ਵਾਰ ਦੀ ਥਾਂ ਸ਼ੂਨ੍ਯ ਜਾਂ ਵੱਧ ਵਾਰ ਮੈਚ ਹੋ ਸਕਦਾ ਹੈ।
ਉਦਾਹਰਨ ਲਈ, ca*t 'ct' (0 'a' ਅੱਖਰ), 'cat' (1 'a'), 'caaat' (3 'a' ਅੱਖਰ), ਆਦਿ ਨਾਲ ਮੈਚ ਕਰੇਗਾ।
* ਵਰਗੀਆਂ ਦੁਹਰਾਵਾਂ greedy ਹੁੰਦੀਆਂ ਹਨ; ਜਦੋਂ ਕੋਈ RE ਦੁਹਰਾਈ ਜਾਂਦੀ ਹੈ, ਤਾਂ matching engine ਇਸਨੂੰ ਸੰਭਵ ਹੋ ਸਕਣ ਵਾਲੀਆਂ ਸਭ ਤੋਂ ਵੱਧ ਵਾਰ ਦੁਹਰਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦਾ ਹੈ। ਜੇ ਪੈਟਰਨ ਦੇ ਬਾਅਦ ਵਾਲੇ ਭਾਗ ਮੈਚ ਨਹੀਂ ਕਰਦੇ, ਤਾਂ matching engine ਪਿੱਛੇ ਹਟਦਾ ਹੈ ਅਤੇ ਘੱਟ ਦੁਹਰਾਵਾਂ ਨਾਲ ਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰਦਾ ਹੈ।
ਇੱਕ ਕਦਮ-ਦਰ-ਕਦਮ ਉਦਾਹਰਨ ਇਸਨੂੰ ਹੋਰ ਸਪਸ਼ਟ ਕਰੇਗੀ। ਆਓ expression a[bcd]*b ਨੂੰ ਵੇਖੀਏ। ਇਹ ਅੱਖਰ 'a' ਨਾਲ ਮੈਚ ਕਰਦੀ ਹੈ, ਫਿਰ class [bcd] ਵਿੱਚੋਂ ਸ਼ੂਨ੍ਯ ਜਾਂ ਵੱਧ ਅੱਖਰਾਂ ਨਾਲ, ਅਤੇ ਅੰਤ ਵਿੱਚ 'b' ਨਾਲ ਖਤਮ ਹੁੰਦੀ ਹੈ। ਹੁਣ ਕਲਪਨਾ ਕਰੋ ਕਿ ਇਸ RE ਨੂੰ string 'abcbd' ਨਾਲ ਮੈਚ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ।
ਕਦਮ |
ਮੈਚ ਕੀਤਾ ਗਿਆ |
ਵਿਆਖਿਆ |
|---|---|---|
1 |
|
RE ਵਿੱਚ ਮੌਜੂਦ |
2 |
|
Matching engine |
3 |
ਅਸਫਲਤਾ |
Engine |
4 |
|
ਪਿੱਛੇ ਹਟੋ ਤਾਂ ਜੋ |
5 |
ਅਸਫਲਤਾ |
ਮੁੜ |
6 |
|
ਮੁੜ ਪਿੱਛੇ ਹਟੋ ਤਾਂ ਜੋ |
7 |
|
ਮੁੜ |
ਹੁਣ RE ਦਾ ਅੰਤ ਆ ਗਿਆ ਹੈ ਅਤੇ ਇਸ ਨੇ 'abcb' ਨਾਲ ਮੈਚ ਕਰ ਲਿਆ ਹੈ। ਇਹ ਦਰਸਾਉਂਦਾ ਹੈ ਕਿ matching engine ਪਹਿਲਾਂ ਸੰਭਵ ਹੋ ਸਕਣ ਵਾਲੀ ਸਭ ਤੋਂ ਵੱਧ ਹੱਦ ਤੱਕ ਜਾਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦਾ ਹੈ, ਅਤੇ ਜੇ ਮੈਚ ਨਾ ਮਿਲੇ ਤਾਂ ਹੌਲੀ-ਹੌਲੀ ਪਿੱਛੇ ਹਟਦਾ ਹੈ ਅਤੇ RE ਦੇ ਬਾਕੀ ਭਾਗ ਨੂੰ ਵਾਰ-ਵਾਰ ਮੁੜ ਅਜ਼ਮਾਉਂਦਾ ਹੈ। ਇਹ ਤਦ ਤੱਕ ਪਿੱਛੇ ਹਟਦਾ ਰਹੇਗਾ ਜਦ ਤੱਕ [bcd]* ਲਈ ਸ਼ੂਨ੍ਯ ਮੈਚ ਵੀ ਅਜ਼ਮਾਏ ਨਾ ਜਾ ਚੁੱਕੇ ਹੋਣ। ਜੇ ਫਿਰ ਵੀ ਮੈਚ ਨਾ ਮਿਲੇ, ਤਾਂ engine ਨਤੀਜਾ ਕੱਢੇਗਾ ਕਿ ਇਹ ਸਟਰਿੰਗ RE ਨਾਲ ਬਿਲਕੁਲ ਵੀ ਮੈਚ ਨਹੀਂ ਕਰਦੀ।
ਇੱਕ ਹੋਰ ਦੁਹਰਾਉਣ ਵਾਲਾ metacharacter + ਹੈ, ਜੋ ਇੱਕ ਜਾਂ ਵੱਧ ਵਾਰ ਮੈਚ ਕਰਦਾ ਹੈ। * ਅਤੇ + ਵਿਚਕਾਰ ਅੰਤਰ ਨੂੰ ਧਿਆਨ ਨਾਲ ਸਮਝੋ; * ਸ਼ੂਨ੍ਯ ਜਾਂ ਵੱਧ ਵਾਰ ਮੈਚ ਕਰਦਾ ਹੈ, ਇਸ ਲਈ ਦੁਹਰਾਈ ਜਾ ਰਹੀ ਚੀਜ਼ ਮੌਜੂਦ ਨਾ ਵੀ ਹੋ ਸਕਦੀ ਹੈ, ਜਦਕਿ + ਲਈ ਘੱਟੋ-ਘੱਟ ਇੱਕ occurrence ਲਾਜ਼ਮੀ ਹੈ। ਇਸੇ ਤਰ੍ਹਾਂ ਦੀ ਉਦਾਹਰਨ ਵਿੱਚ, ca+t 'cat' (1 'a'), 'caaat' (3 'a'\ s) ਨਾਲ ਮੈਚ ਕਰੇਗਾ, ਪਰ 'ct' ਨਾਲ ਮੈਚ ਨਹੀਂ ਕਰੇਗਾ।
ਹੋਰ ਦੋ repeating operators ਜਾਂ quantifiers ਵੀ ਹਨ। ਪ੍ਰਸ਼ਨ ਚਿੰਨ੍ਹ ? ਇੱਕ ਵਾਰ ਜਾਂ ਸ਼ੂਨ੍ਯ ਵਾਰ ਮੈਚ ਕਰਦਾ ਹੈ; ਤੁਸੀਂ ਇਸਨੂੰ ਕਿਸੇ ਚੀਜ਼ ਨੂੰ ਵਿਕਲਪਿਕ ਬਣਾਉਣ ਵਾਂਗ ਸਮਝ ਸਕਦੇ ਹੋ। ਉਦਾਹਰਨ ਲਈ, home-?brew 'homebrew' ਅਤੇ 'home-brew' ਦੋਵਾਂ ਨਾਲ ਮੈਚ ਕਰੇਗਾ।
ਸਭ ਤੋਂ ਜਟਿਲ quantifier {m,n} ਹੈ, ਜਿੱਥੇ m ਅਤੇ n ਦਸ਼ਮਲਵ ਪੂਰਨ ਅੰਕ ਹੁੰਦੇ ਹਨ। ਇਸਦਾ ਅਰਥ ਹੈ ਕਿ ਘੱਟੋ-ਘੱਟ m ਦੁਹਰਾਵਾਂ ਅਤੇ ਵੱਧ ਤੋਂ ਵੱਧ n ਦੁਹਰਾਵਾਂ ਹੋਣੀਆਂ ਚਾਹੀਦੀਆਂ ਹਨ। ਉਦਾਹਰਨ ਲਈ, a/{1,3}b 'a/b', 'a//b' ਅਤੇ 'a///b' ਨਾਲ ਮੈਚ ਕਰੇਗਾ। ਇਹ 'ab' ਨਾਲ ਮੈਚ ਨਹੀਂ ਕਰੇਗਾ ਕਿਉਂਕਿ ਇਸ ਵਿੱਚ ਕੋਈ slash ਨਹੀਂ ਹੈ, ਅਤੇ ਨਾ ਹੀ 'a////b' ਨਾਲ ਕਿਉਂਕਿ ਇਸ ਵਿੱਚ ਚਾਰ slash ਹਨ।
ਤੁਸੀਂ m ਜਾਂ n ਵਿੱਚੋਂ ਕਿਸੇ ਇੱਕ ਨੂੰ ਛੱਡ ਸਕਦੇ ਹੋ; ਅਜਿਹੇ ਮਾਮਲੇ ਵਿੱਚ ਗੁੰਮ ਮੁੱਲ ਲਈ ਇੱਕ ਉਚਿਤ ਮੁੱਲ ਮੰਨਿਆ ਜਾਂਦਾ ਹੈ। m ਨੂੰ ਛੱਡਣ ਦਾ ਅਰਥ ਹੇਠਲੀ ਸੀਮਾ 0 ਮੰਨਿਆ ਜਾਂਦਾ ਹੈ, ਜਦਕਿ n ਨੂੰ ਛੱਡਣ ਦਾ ਅਰਥ ਉੱਪਰੀ ਸੀਮਾ ਅਨੰਤ ਹੋ ਜਾਂਦੀ ਹੈ।
ਸਭ ਤੋਂ ਸਧਾਰਣ ਰੂਪ {m} ਪਿਛਲੇ ਆਈਟਮ ਨਾਲ ਬਿਲਕੁਲ m ਵਾਰ ਮੈਚ ਕਰਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, a/{2}b ਸਿਰਫ਼ 'a//b' ਨਾਲ ਹੀ ਮੈਚ ਕਰੇਗਾ।
ਜੋ ਪਾਠਕ reductionist ਸੋਚ ਰੱਖਦੇ ਹਨ ਉਹ ਧਿਆਨ ਦੇ ਸਕਦੇ ਹਨ ਕਿ ਬਾਕੀ ਤਿੰਨ quantifiers ਨੂੰ ਵੀ ਇਸ notation ਨਾਲ ਦਰਸਾਇਆ ਜਾ ਸਕਦਾ ਹੈ। {0,} * ਦੇ ਬਰਾਬਰ ਹੈ, {1,} + ਦੇ ਬਰਾਬਰ ਹੈ ਅਤੇ {0,1} ? ਦੇ ਬਰਾਬਰ ਹੈ। ਜਿੱਥੇ ਸੰਭਵ ਹੋਵੇ, *, + ਜਾਂ ? ਵਰਤਣਾ ਬਿਹਤਰ ਹੈ ਕਿਉਂਕਿ ਇਹ ਛੋਟੇ ਅਤੇ ਪੜ੍ਹਨ ਵਿੱਚ ਆਸਾਨ ਹੁੰਦੇ ਹਨ।
ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਦੀ ਵਰਤੋਂ¶
ਹੁਣ ਜਦੋਂ ਅਸੀਂ ਕੁਝ ਸਧਾਰਣ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਬਾਰੇ ਵੇਖ ਲਿਆ ਹੈ, ਤਾਂ Python ਵਿੱਚ ਅਸੀਂ ਉਨ੍ਹਾਂ ਦੀ ਵਰਤੋਂ ਅਸਲ ਵਿੱਚ ਕਿਵੇਂ ਕਰਦੇ ਹਾਂ? re ਮੋਡੀਊਲ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ engine ਲਈ ਇੱਕ interface ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਤੁਸੀਂ REs ਨੂੰ objects ਵਿੱਚ compile ਕਰ ਸਕਦੇ ਹੋ ਅਤੇ ਫਿਰ ਉਨ੍ਹਾਂ ਨਾਲ matching operations ਕਰ ਸਕਦੇ ਹੋ।
ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਨੂੰ compile ਕਰਨਾ¶
ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਨੂੰ pattern objects ਵਿੱਚ compile ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਵੱਖ-ਵੱਖ ਕਾਰਵਾਈਆਂ ਲਈ methods ਹੁੰਦੀਆਂ ਹਨ, ਜਿਵੇਂ pattern matches ਖੋਜਣਾ ਜਾਂ string substitutions ਕਰਨਾ।
>>> import re
>>> p = re.compile('ab*')
>>> p
re.compile('ab*')
re.compile() ਇੱਕ ਵਿਕਲਪਿਕ flags argument ਵੀ ਸਵੀਕਾਰ ਕਰਦਾ ਹੈ, ਜਿਸਦੀ ਵਰਤੋਂ ਵੱਖ-ਵੱਖ ਵਿਸ਼ੇਸ਼ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਅਤੇ syntax variations ਨੂੰ ਸਮਰੱਥ ਕਰਨ ਲਈ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਉਪਲਬਧ settings ਬਾਰੇ ਅਸੀਂ ਬਾਅਦ ਵਿੱਚ ਗੱਲ ਕਰਾਂਗੇ, ਪਰ ਇਸ ਵੇਲੇ ਇੱਕ ਉਦਾਹਰਨ ਕਾਫ਼ੀ ਹੈ:
>>> p = re.compile('ab*', re.IGNORECASE)
RE ਨੂੰ re.compile() ਵਿੱਚ ਇੱਕ string ਵਜੋਂ ਪਾਸ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। REs ਨੂੰ strings ਵਜੋਂ ਹੀ ਸੰਭਾਲਿਆ ਜਾਂਦਾ ਹੈ ਕਿਉਂਕਿ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ Python ਭਾਸ਼ਾ ਦੇ ਮੁੱਖ ਹਿੱਸੇ ਦਾ ਭਾਗ ਨਹੀਂ ਹਨ ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਦਰਸਾਉਣ ਲਈ ਕੋਈ ਵੱਖਰਾ syntax ਨਹੀਂ ਬਣਾਇਆ ਗਿਆ। (ਕਈ ਐਪਲੀਕੇਸ਼ਨਾਂ ਨੂੰ REs ਦੀ ਲੋੜ ਹੀ ਨਹੀਂ ਹੁੰਦੀ, ਇਸ ਲਈ ਭਾਸ਼ਾ ਦੇ specification ਨੂੰ ਬੇਲੋੜਾ ਵੱਡਾ ਬਣਾਉਣ ਦੀ ਲੋੜ ਨਹੀਂ ਹੈ।) ਇਸ ਦੀ ਬਜਾਏ, re ਮੋਡੀਊਲ Python ਨਾਲ ਸ਼ਾਮਲ ਇੱਕ C extension module ਹੈ, ਬਿਲਕੁਲ socket ਜਾਂ zlib ਮੋਡੀਊਲਾਂ ਵਾਂਗ।
REs ਨੂੰ strings ਵਿੱਚ ਰੱਖਣ ਨਾਲ Python ਭਾਸ਼ਾ ਸਧਾਰਣ ਰਹਿੰਦੀ ਹੈ, ਪਰ ਇਸਦਾ ਇੱਕ ਨੁਕਸਾਨ ਵੀ ਹੈ, ਜੋ ਅਗਲੇ ਭਾਗ ਦਾ ਵਿਸ਼ਾ ਹੈ।
ਬੈਕਸਲੈਸ਼ ਦੀ ਸਮੱਸਿਆ¶
ਜਿਵੇਂ ਪਹਿਲਾਂ ਦੱਸਿਆ ਗਿਆ ਹੈ, regular expressions ਖਾਸ ਰੂਪਾਂ ਨੂੰ ਦਰਸਾਉਣ ਜਾਂ ਖਾਸ ਅੱਖਰਾਂ ਨੂੰ ਉਨ੍ਹਾਂ ਦੇ ਵਿਸ਼ੇਸ਼ ਅਰਥ ਤੋਂ ਬਿਨਾਂ ਵਰਤਣ ਲਈ backslash ਅੱਖਰ ('\') ਦੀ ਵਰਤੋਂ ਕਰਦੀਆਂ ਹਨ। ਇਹ Python ਵਿੱਚ string literals ਦੇ ਅੰਦਰ ਉਸੇ ਅੱਖਰ ਦੀ ਇਸੇ ਉਦੇਸ਼ ਲਈ ਕੀਤੀ ਜਾਣ ਵਾਲੀ ਵਰਤੋਂ ਨਾਲ ਟਕਰਾਉਂਦਾ ਹੈ।
ਮੰਨ ਲਓ ਤੁਸੀਂ ਇੱਕ ਅਜਿਹੀ RE ਲਿਖਣਾ ਚਾਹੁੰਦੇ ਹੋ ਜੋ \section ਸਟਰਿੰਗ ਨਾਲ ਮੈਚ ਕਰੇ, ਜੋ ਕਿਸੇ LaTeX ਫਾਈਲ ਵਿੱਚ ਮਿਲ ਸਕਦੀ ਹੈ। ਇਹ ਸਮਝਣ ਲਈ ਕਿ ਪ੍ਰੋਗਰਾਮ ਕੋਡ ਵਿੱਚ ਕੀ ਲਿਖਣਾ ਹੈ, ਪਹਿਲਾਂ ਉਸ ਸਟਰਿੰਗ ਤੋਂ ਸ਼ੁਰੂ ਕਰੋ ਜਿਸ ਨਾਲ ਮੈਚ ਕਰਨਾ ਹੈ। ਫਿਰ ਤੁਹਾਨੂੰ ਹਰ backslash ਅਤੇ ਹੋਰ metacharacters ਤੋਂ ਪਹਿਲਾਂ ਇੱਕ backslash ਲਗਾ ਕੇ ਉਨ੍ਹਾਂ ਨੂੰ escape ਕਰਨਾ ਪਵੇਗਾ, ਜਿਸ ਨਾਲ \\section ਸਟਰਿੰਗ ਬਣੇਗੀ। re.compile() ਨੂੰ ਦਿੱਤੀ ਜਾਣ ਵਾਲੀ resulting string \\section ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ। ਪਰ ਇਸਨੂੰ Python string literal ਵਜੋਂ ਦਰਸਾਉਣ ਲਈ ਦੋਵੇਂ backslashes ਨੂੰ ਮੁੜ escape ਕਰਨਾ ਪਵੇਗਾ।
ਅੱਖਰ |
ਪੜਾਅ |
|---|---|
|
ਮੈਚ ਕੀਤੀ ਜਾਣ ਵਾਲੀ ਟੈਕਸਟ ਸਟਰਿੰਗ |
|
|
|
string literal ਲਈ escape ਕੀਤੇ ਗਏ backslashes |
ਸੰਖੇਪ ਵਿੱਚ, ਇੱਕ literal backslash ਨਾਲ ਮੈਚ ਕਰਨ ਲਈ RE string ਵਜੋਂ '\\\\' ਲਿਖਣਾ ਪੈਂਦਾ ਹੈ, ਕਿਉਂਕਿ regular expression \\ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ ਅਤੇ ਹਰ backslash ਨੂੰ ਇੱਕ ਆਮ Python string literal ਦੇ ਅੰਦਰ \\ ਵਜੋਂ ਦਰਸਾਉਣਾ ਪੈਂਦਾ ਹੈ। ਜਿਨ੍ਹਾਂ REs ਵਿੱਚ ਵਾਰ-ਵਾਰ backslashes ਆਉਂਦੇ ਹਨ, ਉੱਥੇ ਇਸ ਕਾਰਨ ਬਹੁਤ ਸਾਰੇ ਦੁਹਰਾਏ ਹੋਏ backslashes ਲਿਖਣੇ ਪੈਂਦੇ ਹਨ ਅਤੇ resulting strings ਨੂੰ ਸਮਝਣਾ ਔਖਾ ਹੋ ਜਾਂਦਾ ਹੈ।
ਇਸਦਾ ਹੱਲ regular expressions ਲਈ Python ਦੀ raw string notation ਵਰਤਣਾ ਹੈ; 'r' ਨਾਲ ਸ਼ੁਰੂ ਹੋਣ ਵਾਲੇ string literal ਵਿੱਚ backslashes ਨੂੰ ਕਿਸੇ ਖਾਸ ਤਰੀਕੇ ਨਾਲ ਨਹੀਂ ਸੰਭਾਲਿਆ ਜਾਂਦਾ, ਇਸ ਲਈ r"\n" ਇੱਕ ਦੋ-ਅੱਖਰੀ ਸਟਰਿੰਗ ਹੈ ਜਿਸ ਵਿੱਚ '\' ਅਤੇ 'n' ਹੁੰਦੇ ਹਨ, ਜਦਕਿ "\n" ਇੱਕ ਇਕੱਲੇ newline ਅੱਖਰ ਵਾਲੀ ਸਟਰਿੰਗ ਹੈ। Python ਕੋਡ ਵਿੱਚ regular expressions ਅਕਸਰ ਇਸ raw string notation ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਲਿਖੀਆਂ ਜਾਂਦੀਆਂ ਹਨ।
ਇਸ ਤੋਂ ਇਲਾਵਾ, ਕੁਝ special escape sequences ਜੋ regular expressions ਵਿੱਚ ਵੈਧ ਹਨ ਪਰ Python string literals ਵਿੱਚ ਵੈਧ ਨਹੀਂ ਹਨ, ਹੁਣ SyntaxWarning ਪੈਦਾ ਕਰਦੀਆਂ ਹਨ ਅਤੇ ਭਵਿੱਖ ਵਿੱਚ SyntaxError ਬਣ ਜਾਣਗੀਆਂ। ਇਸਦਾ ਅਰਥ ਹੈ ਕਿ ਜੇ raw string notation ਜਾਂ backslashes ਨੂੰ escape ਕਰਨ ਦੀ ਵਿਧੀ ਨਾ ਵਰਤੀ ਜਾਵੇ, ਤਾਂ ਉਹ sequences ਅਵੈਧ ਮੰਨੀਆਂ ਜਾਣਗੀਆਂ।
ਆਮ ਸਟਰਿੰਗ |
Raw string |
|---|---|
|
|
|
|
|
|
ਮੈਚ ਕਰਨਾ¶
ਜਦੋਂ ਤੁਹਾਡੇ ਕੋਲ ਇੱਕ compiled regular expression ਨੂੰ ਦਰਸਾਉਣ ਵਾਲਾ object ਹੋਵੇ, ਤਾਂ ਤੁਸੀਂ ਉਸ ਨਾਲ ਕੀ ਕਰਦੇ ਹੋ? Pattern objects ਵਿੱਚ ਕਈ methods ਅਤੇ attributes ਹੁੰਦੇ ਹਨ। ਇੱਥੇ ਸਿਰਫ਼ ਸਭ ਤੋਂ ਮਹੱਤਵਪੂਰਨ ਚੀਜ਼ਾਂ ਬਾਰੇ ਗੱਲ ਕੀਤੀ ਜਾਵੇਗੀ; ਪੂਰੀ ਸੂਚੀ ਲਈ re ਦੇ ਦਸਤਾਵੇਜ਼ ਵੇਖੋ।
Method/Attribute |
ਉਦੇਸ਼ |
|---|---|
|
ਇੱਕ ਸਟਰਿੰਗ ਵਿੱਚੋਂ ਲੰਘਦੇ ਹੋਏ ਉਹ ਕੋਈ ਵੀ ਸਥਾਨ ਲੱਭਦਾ ਹੈ ਜਿੱਥੇ ਇਹ RE ਮੈਚ ਕਰਦੀ ਹੈ। |
|
ਇਹ ਨਿਰਧਾਰਤ ਕਰਦਾ ਹੈ ਕਿ RE ਸਟਰਿੰਗ ਦੇ ਸ਼ੁਰੂ ਵਿੱਚ ਮੈਚ ਕਰਦੀ ਹੈ ਜਾਂ ਨਹੀਂ। ਪਹਿਲਾਂ ਇਸਦਾ ਨਾਮ match() ਸੀ। |
|
ਉਹ ਸਾਰੀਆਂ substrings ਲੱਭਦਾ ਹੈ ਜਿੱਥੇ RE ਮੈਚ ਕਰਦੀ ਹੈ ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਇੱਕ list ਵਜੋਂ ਵਾਪਸ ਕਰਦਾ ਹੈ। |
|
ਉਹ ਸਾਰੀਆਂ substrings ਲੱਭਦਾ ਹੈ ਜਿੱਥੇ RE ਮੈਚ ਕਰਦੀ ਹੈ ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਇੱਕ iterator ਵਜੋਂ ਵਾਪਸ ਕਰਦਾ ਹੈ। |
search() ਅਤੇ prefixmatch() ਜੇ ਕੋਈ ਮੈਚ ਨਾ ਮਿਲੇ ਤਾਂ None ਵਾਪਸ ਕਰਦੀਆਂ ਹਨ। ਜੇ ਇਹ ਸਫਲ ਹੋਣ, ਤਾਂ ਇੱਕ match object instance ਵਾਪਸ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਜਿਸ ਵਿੱਚ ਮੈਚ ਬਾਰੇ ਜਾਣਕਾਰੀ ਹੁੰਦੀ ਹੈ: ਇਹ ਕਿੱਥੇ ਸ਼ੁਰੂ ਅਤੇ ਖਤਮ ਹੁੰਦਾ ਹੈ, ਕਿਹੜੀ substring ਮੈਚ ਹੋਈ ਅਤੇ ਹੋਰ ਜਾਣਕਾਰੀ।
ਤੁਸੀਂ re ਮੋਡੀਊਲ ਨਾਲ ਇੰਟਰਐਕਟਿਵ ਤੌਰ 'ਤੇ ਪ੍ਰਯੋਗ ਕਰਕੇ ਇਸ ਬਾਰੇ ਸਿੱਖ ਸਕਦੇ ਹੋ।
ਇਸ HOWTO ਵਿੱਚ ਉਦਾਹਰਨਾਂ ਲਈ ਮਿਆਰੀ Python interpreter ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਗਈ ਹੈ। ਪਹਿਲਾਂ Python interpreter ਚਲਾਓ, re ਮੋਡੀਊਲ import ਕਰੋ ਅਤੇ ਇੱਕ RE compile ਕਰੋ:
>>> import re
>>> p = re.compile('[a-z]+')
>>> p
re.compile('[a-z]+')
ਹੁਣ ਤੁਸੀਂ RE [a-z]+ ਦੇ ਵਿਰੁੱਧ ਵੱਖ-ਵੱਖ ਸਟਰਿੰਗਾਂ ਨੂੰ ਮੈਚ ਕਰਕੇ ਵੇਖ ਸਕਦੇ ਹੋ। ਇੱਕ ਖਾਲੀ ਸਟਰਿੰਗ ਨਾਲ ਕੋਈ ਮੈਚ ਨਹੀਂ ਹੋਣਾ ਚਾਹੀਦਾ, ਕਿਉਂਕਿ + ਦਾ ਅਰਥ ਹੈ "ਇੱਕ ਜਾਂ ਵੱਧ ਦੁਹਰਾਵਾਂ"। ਇਸ ਸਥਿਤੀ ਵਿੱਚ search() None ਵਾਪਸ ਕਰੇਗਾ, ਜਿਸ ਕਾਰਨ interpreter ਕੋਈ output ਨਹੀਂ ਦਿਖਾਏਗਾ। ਇਸਨੂੰ ਸਪਸ਼ਟ ਕਰਨ ਲਈ ਤੁਸੀਂ search() ਦਾ ਨਤੀਜਾ ਸਿੱਧਾ print ਕਰ ਸਕਦੇ ਹੋ।
>>> p.search("")
>>> print(p.search(""))
None
ਹੁਣ ਇਸਨੂੰ ਇੱਕ ਅਜਿਹੀ ਸਟਰਿੰਗ ਉੱਤੇ ਅਜ਼ਮਾਈਏ ਜਿਸ ਨਾਲ ਇਹ ਮੈਚ ਕਰਨੀ ਚਾਹੀਦੀ ਹੈ, ਜਿਵੇਂ tempo। ਇਸ ਸਥਿਤੀ ਵਿੱਚ search() ਇੱਕ match object ਵਾਪਸ ਕਰੇਗਾ, ਇਸ ਲਈ ਨਤੀਜੇ ਨੂੰ ਬਾਅਦ ਵਿੱਚ ਵਰਤਣ ਲਈ ਇੱਕ variable ਵਿੱਚ ਸਟੋਰ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ।
>>> m = p.search('tempo')
>>> m
<re.Match object; span=(0, 5), match='tempo'>
ਹੁਣ ਤੁਸੀਂ matching string ਬਾਰੇ ਜਾਣਕਾਰੀ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ match object ਨੂੰ ਪੁੱਛ ਸਕਦੇ ਹੋ। Match object instances ਵਿੱਚ ਕਈ methods ਅਤੇ attributes ਹੁੰਦੇ ਹਨ; ਸਭ ਤੋਂ ਮਹੱਤਵਪੂਰਨ ਇਹ ਹਨ:
Method/Attribute |
ਉਦੇਸ਼ |
|---|---|
|
RE ਦੁਆਰਾ ਮੈਚ ਕੀਤੀ ਗਈ ਸਟਰਿੰਗ ਵਾਪਸ ਕਰਦਾ ਹੈ |
|
ਮੈਚ ਦੀ ਸ਼ੁਰੂਆਤੀ ਸਥਿਤੀ ਵਾਪਸ ਕਰਦਾ ਹੈ |
|
ਮੈਚ ਦੀ ਅੰਤਿਮ ਸਥਿਤੀ ਵਾਪਸ ਕਰਦਾ ਹੈ |
|
ਮੈਚ ਦੀਆਂ (start, end) ਸਥਿਤੀਆਂ ਵਾਲਾ ਇੱਕ tuple ਵਾਪਸ ਕਰਦਾ ਹੈ |
ਇਨ੍ਹਾਂ methods ਨੂੰ ਅਜ਼ਮਾਉਣ ਨਾਲ ਉਨ੍ਹਾਂ ਦਾ ਅਰਥ ਤੁਰੰਤ ਸਪਸ਼ਟ ਹੋ ਜਾਵੇਗਾ:
>>> m.group()
'tempo'
>>> m.start(), m.end()
(0, 5)
>>> m.span()
(0, 5)
group() ਉਹ substring ਵਾਪਸ ਕਰਦਾ ਹੈ ਜਿਸ ਨਾਲ RE ਮੈਚ ਹੋਈ ਸੀ। start() ਅਤੇ end() ਮੈਚ ਦੇ ਸ਼ੁਰੂ ਅਤੇ ਅੰਤ ਦੇ index ਵਾਪਸ ਕਰਦੇ ਹਨ। span() ਇੱਕ ਹੀ tuple ਵਿੱਚ ਦੋਵੇਂ index ਵਾਪਸ ਕਰਦਾ ਹੈ। Patterns ਦੀ search() method ਪੂਰੀ ਸਟਰਿੰਗ ਵਿੱਚ ਖੋਜ ਕਰਦੀ ਹੈ, ਇਸ ਲਈ ਮੈਚ ਲਾਜ਼ਮੀ ਨਹੀਂ ਕਿ index 0 ਤੋਂ ਸ਼ੁਰੂ ਹੋਵੇ। ਹਾਲਾਂਕਿ prefixmatch() ਸਿਰਫ਼ ਇਹ ਜਾਂਚਦੀ ਹੈ ਕਿ RE ਸਟਰਿੰਗ ਦੇ ਸ਼ੁਰੂ ਵਿੱਚ ਮੈਚ ਕਰਦੀ ਹੈ ਜਾਂ ਨਹੀਂ, ਇਸ ਲਈ ਉਸ ਸਥਿਤੀ ਵਿੱਚ start() ਹਮੇਸ਼ਾਂ 0 ਹੋਵੇਗਾ।
>>> m = p.search('::: message'); print(m)
<re.Match object; span=(4, 11), match='message'>
>>> m.group()
'message'
>>> m.span()
(4, 11)
>>> print(p.prefixmatch('::: message'))
None
ਅਸਲ ਪ੍ਰੋਗਰਾਮਾਂ ਵਿੱਚ ਸਭ ਤੋਂ ਆਮ ਤਰੀਕਾ ਇਹ ਹੁੰਦਾ ਹੈ ਕਿ match object ਨੂੰ ਇੱਕ variable ਵਿੱਚ ਸਟੋਰ ਕੀਤਾ ਜਾਵੇ ਅਤੇ ਫਿਰ ਜਾਂਚਿਆ ਜਾਵੇ ਕਿ ਕੀ ਉਹ None ਹੈ। ਆਮ ਤੌਰ 'ਤੇ ਇਹ ਇਸ ਤਰ੍ਹਾਂ ਦਿਖਾਈ ਦਿੰਦਾ ਹੈ:
p = re.compile( ... )
m = p.search( 'string goes here' )
if m:
print('Match found: ', m.group())
else:
print('No match')
Pattern ਦੀਆਂ ਦੋ methods ਕਿਸੇ pattern ਲਈ ਸਾਰੇ ਮੈਚ ਵਾਪਸ ਕਰਦੀਆਂ ਹਨ। findall() ਮੈਚ ਹੋਈਆਂ ਸਟਰਿੰਗਾਂ ਦੀ ਇੱਕ list ਵਾਪਸ ਕਰਦੀ ਹੈ:
>>> p = re.compile(r'\d+')
>>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')
['12', '11', '10']
ਇਸ ਉਦਾਹਰਨ ਵਿੱਚ r prefix, ਜੋ literal ਨੂੰ raw string literal ਬਣਾਉਂਦਾ ਹੈ, ਲਾਜ਼ਮੀ ਹੈ ਕਿਉਂਕਿ ਇੱਕ ਆਮ "cooked" string literal ਵਿੱਚ ਮੌਜੂਦ escape sequences ਜਿਨ੍ਹਾਂ ਨੂੰ Python ਨਹੀਂ ਪਛਾਣਦਾ ਭਾਵੇਂ regular expressions ਪਛਾਣ ਲੈਣ, ਹੁਣ SyntaxWarning ਪੈਦਾ ਕਰਦੀਆਂ ਹਨ ਅਤੇ ਭਵਿੱਖ ਵਿੱਚ SyntaxError ਬਣ ਜਾਣਗੀਆਂ। ਬੈਕਸਲੈਸ਼ ਦੀ ਸਮੱਸਿਆ ਵੇਖੋ।
findall() ਨੂੰ ਨਤੀਜਾ ਵਾਪਸ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਪੂਰੀ list ਬਣਾਉਣੀ ਪੈਂਦੀ ਹੈ। finditer() method ਇੱਕ iterator ਦੇ ਰੂਪ ਵਿੱਚ match object instances ਦੀ ਲੜੀ ਵਾਪਸ ਕਰਦੀ ਹੈ:
>>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...')
>>> iterator
<callable_iterator object at 0x...>
>>> for match in iterator:
... print(match.span())
...
(0, 2)
(22, 24)
(29, 31)
ਮੋਡੀਊਲ-ਪੱਧਰੀ ਫੰਕਸ਼ਨ¶
ਤੁਹਾਨੂੰ pattern object ਬਣਾਕੇ ਉਸ ਦੀਆਂ methods ਨੂੰ ਕਾਲ ਕਰਨ ਦੀ ਲੋੜ ਨਹੀਂ ਹੈ; re ਮੋਡੀਊਲ search(), prefixmatch(), findall(), sub() ਆਦਿ top-level functions ਵੀ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ। ਇਹ functions ਸੰਬੰਧਿਤ pattern method ਵਾਲੇ ਹੀ arguments ਲੈਂਦੀਆਂ ਹਨ, ਸਿਰਫ਼ RE string ਨੂੰ ਪਹਿਲੇ argument ਵਜੋਂ ਜੋੜਿਆ ਜਾਂਦਾ ਹੈ, ਅਤੇ ਇਹ ਵੀ None ਜਾਂ match object instance ਵਾਪਸ ਕਰਦੀਆਂ ਹਨ।
>>> print(re.prefixmatch(r'From\s+', 'Fromage amk'))
None
>>> re.prefixmatch(r'From\s+', 'From amk Thu May 14 19:12:10 1998')
<re.Match object; span=(0, 5), match='From '>
ਅੰਦਰੂਨੀ ਤੌਰ 'ਤੇ, ਇਹ functions ਤੁਹਾਡੇ ਲਈ ਇੱਕ pattern object ਬਣਾਉਂਦੀਆਂ ਹਨ ਅਤੇ ਉਸ ਉੱਤੇ ਉਚਿਤ method ਨੂੰ ਕਾਲ ਕਰਦੀਆਂ ਹਨ। ਇਹ compiled object ਨੂੰ cache ਵਿੱਚ ਵੀ ਸਟੋਰ ਕਰਦੀਆਂ ਹਨ, ਇਸ ਲਈ ਇੱਕੋ RE ਨਾਲ ਭਵਿੱਖ ਦੀਆਂ calls ਨੂੰ pattern ਨੂੰ ਮੁੜ-ਮੁੜ parse ਕਰਨ ਦੀ ਲੋੜ ਨਹੀਂ ਪਵੇਗੀ।
ਕੀ ਤੁਹਾਨੂੰ ਇਹ module-level functions ਵਰਤਣੀਆਂ ਚਾਹੀਦੀਆਂ ਹਨ ਜਾਂ pattern ਪ੍ਰਾਪਤ ਕਰਕੇ ਉਸ ਦੀਆਂ methods ਨੂੰ ਖੁਦ ਕਾਲ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ? ਜੇ ਤੁਸੀਂ ਕਿਸੇ loop ਦੇ ਅੰਦਰ regex ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੇ ਹੋ, ਤਾਂ ਉਸਨੂੰ ਪਹਿਲਾਂ compile ਕਰ ਲੈਣਾ ਕੁਝ function calls ਬਚਾ ਸਕਦਾ ਹੈ। Loops ਤੋਂ ਬਾਹਰ, internal cache ਕਰਕੇ ਦੋਹਾਂ ਤਰੀਕਿਆਂ ਵਿੱਚ ਬਹੁਤ ਘੱਟ ਫ਼ਰਕ ਹੁੰਦਾ ਹੈ।
ਕੰਪਾਈਲੇਸ਼ਨ ਫਲੈਗ¶
Compilation flags ਤੁਹਾਨੂੰ regular expressions ਦੇ ਕੰਮ ਕਰਨ ਦੇ ਕੁਝ ਪੱਖਾਂ ਨੂੰ ਬਦਲਣ ਦੀ ਆਗਿਆ ਦਿੰਦੀਆਂ ਹਨ। Flags re ਮੋਡੀਊਲ ਵਿੱਚ ਦੋ ਨਾਵਾਂ ਨਾਲ ਉਪਲਬਧ ਹੁੰਦੀਆਂ ਹਨ: ਇੱਕ ਲੰਮਾ ਨਾਮ ਜਿਵੇਂ IGNORECASE ਅਤੇ ਇੱਕ ਛੋਟਾ, ਇਕ-ਅੱਖਰੀ ਰੂਪ ਜਿਵੇਂ I। (ਜੇ ਤੁਸੀਂ Perl ਦੇ pattern modifiers ਨਾਲ ਜਾਣੂ ਹੋ, ਤਾਂ ਇਕ-ਅੱਖਰੀ ਰੂਪ ਉਹੀ ਅੱਖਰ ਵਰਤਦੇ ਹਨ; ਉਦਾਹਰਨ ਲਈ re.VERBOSE ਦਾ ਛੋਟਾ ਰੂਪ re.X ਹੈ।) ਕਈ flags ਨੂੰ bitwise OR ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਇਕੱਠੇ ਨਿਰਧਾਰਤ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ; ਉਦਾਹਰਨ ਲਈ re.I | re.M ਦੋਵੇਂ I ਅਤੇ M flags ਸੈੱਟ ਕਰਦਾ ਹੈ।
ਹੇਠਾਂ ਉਪਲਬਧ flags ਦੀ ਇੱਕ ਸਾਰਣੀ ਦਿੱਤੀ ਗਈ ਹੈ, ਜਿਸ ਤੋਂ ਬਾਅਦ ਹਰ ਇੱਕ ਦੀ ਹੋਰ ਵਿਸਤ੍ਰਿਤ ਵਿਆਖਿਆ ਦਿੱਤੀ ਗਈ ਹੈ।
Flag |
ਅਰਥ |
|---|---|
|
|
|
|
Case-insensitive ਮੈਚਿੰਗ ਕਰਦਾ ਹੈ। |
|
Locale-aware ਮੈਚਿੰਗ ਕਰਦਾ ਹੈ। |
|
ਬਹੁ-ਲਾਈਨ ਮੈਚਿੰਗ, ਜੋ |
|
ਵਿਸਤ੍ਰਿਤ REs ਨੂੰ ਸਮਰੱਥ ਕਰਦਾ ਹੈ, ਜਿਨ੍ਹਾਂ ਨੂੰ ਹੋਰ ਸਾਫ਼ ਅਤੇ ਸਮਝਣਯੋਗ ਢੰਗ ਨਾਲ ਵਿਵਸਥਿਤ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ। |
- re.I
- re.IGNORECASE
Case-insensitive ਮੈਚਿੰਗ ਕਰਦਾ ਹੈ; character classes ਅਤੇ literal strings case ਨੂੰ ਨਜ਼ਰਅੰਦਾਜ਼ ਕਰਦੇ ਹੋਏ ਅੱਖਰਾਂ ਨਾਲ ਮੈਚ ਕਰਨਗੀਆਂ। ਉਦਾਹਰਨ ਲਈ,
[A-Z]ਛੋਟੇ ਅੱਖਰਾਂ ਨਾਲ ਵੀ ਮੈਚ ਕਰੇਗਾ। ਜਦ ਤੱਕASCIIflag ਦੀ ਵਰਤੋਂ ਕਰਕੇ non-ASCII ਮੈਚਿੰਗ ਨੂੰ ਅਸਮਰੱਥ ਨਾ ਕੀਤਾ ਜਾਵੇ, ਪੂਰੀ Unicode ਮੈਚਿੰਗ ਵੀ ਕੰਮ ਕਰਦੀ ਹੈ। ਜਦੋਂ Unicode patterns[a-z]ਜਾਂ[A-Z]ਨੂੰIGNORECASEflag ਨਾਲ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ, ਤਾਂ ਇਹ 52 ASCII ਅੱਖਰਾਂ ਅਤੇ 4 ਵਾਧੂ non-ASCII ਅੱਖਰਾਂ ਨਾਲ ਵੀ ਮੈਚ ਕਰਦੇ ਹਨ: 'İ' (U+0130), 'ı' (U+0131), 'ſ' (U+017F) ਅਤੇ 'K' (U+212A)।Spam'Spam','spam','spAM'ਅਤੇ'ſpam'ਨਾਲ ਮੈਚ ਕਰੇਗਾ (ਆਖਰੀ ਵਾਲਾ ਸਿਰਫ਼ Unicode mode ਵਿੱਚ)। ਇਹ lowercasing ਮੌਜੂਦਾ locale ਨੂੰ ਧਿਆਨ ਵਿੱਚ ਨਹੀਂ ਰੱਖਦੀ; ਜੇ ਤੁਸੀਂLOCALEflag ਵੀ ਸੈੱਟ ਕਰੋ ਤਾਂ locale ਨੂੰ ਵੀ ਧਿਆਨ ਵਿੱਚ ਰੱਖਿਆ ਜਾਵੇਗਾ।
- re.L
- re.LOCALE
\w,\W,\b,\Bਅਤੇ case-insensitive ਮੈਚਿੰਗ ਨੂੰ Unicode ਡਾਟਾਬੇਸ ਦੀ ਬਜਾਏ ਮੌਜੂਦਾ locale 'ਤੇ ਨਿਰਭਰ ਬਣਾਉਂਦਾ ਹੈ।Locales C ਲਾਇਬ੍ਰੇਰੀ ਦੀ ਇੱਕ ਵਿਸ਼ੇਸ਼ਤਾ ਹਨ, ਜਿਨ੍ਹਾਂ ਦਾ ਉਦੇਸ਼ ਅਜਿਹੇ ਪ੍ਰੋਗਰਾਮ ਲਿਖਣ ਵਿੱਚ ਮਦਦ ਕਰਨਾ ਹੈ ਜੋ ਭਾਸ਼ਾਈ ਅੰਤਰਾਂ ਨੂੰ ਧਿਆਨ ਵਿੱਚ ਰੱਖਣ। ਉਦਾਹਰਨ ਲਈ, ਜੇ ਤੁਸੀਂ encoded French text ਪ੍ਰੋਸੈਸ ਕਰ ਰਹੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਚਾਹੋਗੇ ਕਿ
\w+ਸ਼ਬਦਾਂ ਨਾਲ ਮੈਚ ਕਰੇ, ਪਰ bytes patterns ਵਿੱਚ\wਸਿਰਫ਼[A-Za-z]character class ਨਾਲ ਹੀ ਮੈਚ ਕਰਦਾ ਹੈ; ਇਹéਜਾਂçਨਾਲ ਸੰਬੰਧਿਤ bytes ਨਾਲ ਮੈਚ ਨਹੀਂ ਕਰੇਗਾ। ਜੇ ਤੁਹਾਡਾ ਸਿਸਟਮ ਠੀਕ ਤਰ੍ਹਾਂ ਸੰਰਚਿਤ ਹੈ ਅਤੇ French locale ਚੁਣਿਆ ਗਿਆ ਹੈ, ਤਾਂ ਕੁਝ C functions ਪ੍ਰੋਗਰਾਮ ਨੂੰ ਦੱਸਣਗੀਆਂ ਕਿéਨਾਲ ਸੰਬੰਧਿਤ byte ਨੂੰ ਵੀ ਇੱਕ ਅੱਖਰ ਮੰਨਿਆ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ। Regular expression compile ਕਰਦੇ ਸਮੇਂLOCALEflag ਸੈੱਟ ਕਰਨ ਨਾਲ compiled object\wਲਈ ਇਨ੍ਹਾਂ C functions ਦੀ ਵਰਤੋਂ ਕਰੇਗਾ। ਇਹ ਕੁਝ ਹੌਲਾ ਹੈ, ਪਰ\w+ਨੂੰ French ਸ਼ਬਦਾਂ ਨਾਲ ਉਮੀਦ ਅਨੁਸਾਰ ਮੈਚ ਕਰਨ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। Python 3 ਵਿੱਚ ਇਸ flag ਦੀ ਵਰਤੋਂ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਨਹੀਂ ਕੀਤੀ ਜਾਂਦੀ ਕਿਉਂਕਿ locale mechanism ਕਾਫ਼ੀ ਅਣਭਰੋਸੇਯੋਗ ਹੈ, ਇੱਕ ਸਮੇਂ ਵਿੱਚ ਸਿਰਫ਼ ਇੱਕ "culture" ਨੂੰ ਸੰਭਾਲਦਾ ਹੈ ਅਤੇ ਸਿਰਫ਼ 8-bit locales ਨਾਲ ਕੰਮ ਕਰਦਾ ਹੈ। Python 3 ਵਿੱਚ Unicode (str) patterns ਲਈ Unicode matching ਪਹਿਲਾਂ ਹੀ ਮੂਲ ਰੂਪ ਵਿੱਚ ਸਮਰੱਥ ਹੈ ਅਤੇ ਵੱਖ-ਵੱਖ ਭਾਸ਼ਾਵਾਂ ਅਤੇ locales ਨੂੰ ਸੰਭਾਲ ਸਕਦੀ ਹੈ।
- re.M
- re.MULTILINE
(
^ਅਤੇ$ਬਾਰੇ ਹਾਲੇ ਤੱਕ ਵਿਆਖਿਆ ਨਹੀਂ ਕੀਤੀ ਗਈ; ਇਨ੍ਹਾਂ ਨੂੰ ਹੋਰ metacharacters ਭਾਗ ਵਿੱਚ ਪੇਸ਼ ਕੀਤਾ ਜਾਵੇਗਾ।)ਆਮ ਤੌਰ 'ਤੇ
^ਸਿਰਫ਼ ਸਟਰਿੰਗ ਦੇ ਸ਼ੁਰੂ ਵਿੱਚ ਅਤੇ$ਸਿਰਫ਼ ਸਟਰਿੰਗ ਦੇ ਅੰਤ ਵਿੱਚ (ਅਤੇ ਜੇ ਅੰਤ ਵਿੱਚ newline ਹੋਵੇ ਤਾਂ ਉਸ ਤੋਂ ਤੁਰੰਤ ਪਹਿਲਾਂ) ਮੈਚ ਕਰਦਾ ਹੈ। ਜਦੋਂ ਇਹ flag ਨਿਰਧਾਰਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਤਾਂ^ਸਟਰਿੰਗ ਦੇ ਸ਼ੁਰੂ ਵਿੱਚ ਅਤੇ ਸਟਰਿੰਗ ਦੇ ਅੰਦਰ ਹਰ newline ਤੋਂ ਤੁਰੰਤ ਬਾਅਦ ਵੀ ਮੈਚ ਕਰਦਾ ਹੈ। ਇਸੇ ਤਰ੍ਹਾਂ,$metacharacter ਸਟਰਿੰਗ ਦੇ ਅੰਤ ਅਤੇ ਹਰ ਲਾਈਨ ਦੇ ਅੰਤ (ਹਰ newline ਤੋਂ ਤੁਰੰਤ ਪਹਿਲਾਂ) ਦੋਹਾਂ ਥਾਵਾਂ 'ਤੇ ਮੈਚ ਕਰਦਾ ਹੈ।
- re.S
- re.DOTALL
'.'ਖਾਸ ਅੱਖਰ ਨੂੰ newline ਸਮੇਤ ਕਿਸੇ ਵੀ ਅੱਖਰ ਨਾਲ ਮੈਚ ਕਰਨ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ; ਇਸ flag ਤੋਂ ਬਿਨਾਂ'.'newline ਤੋਂ ਇਲਾਵਾ ਹਰ ਚੀਜ਼ ਨਾਲ ਮੈਚ ਕਰਦਾ ਹੈ।
- re.A
- re.ASCII
\w,\W,\b,\B,\sਅਤੇ\Sਨੂੰ ਪੂਰੀ Unicode matching ਦੀ ਬਜਾਏ ਸਿਰਫ਼ ASCII matching ਕਰਨ ਲਈ ਮਜਬੂਰ ਕਰਦਾ ਹੈ। ਇਹ ਸਿਰਫ਼ Unicode patterns ਲਈ ਹੀ ਅਰਥਪੂਰਨ ਹੈ ਅਤੇ byte patterns ਲਈ ਇਸਨੂੰ ਅਣਡਿੱਠਾ ਕਰ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ।
- re.X
- re.VERBOSE
ਇਹ flag ਤੁਹਾਨੂੰ regular expressions ਨੂੰ ਹੋਰ ਪੜ੍ਹਨਯੋਗ ਢੰਗ ਨਾਲ ਲਿਖਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ ਕਿਉਂਕਿ ਇਹ formatting ਵਿੱਚ ਵੱਧ ਲਚਕਤਾ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ। ਜਦੋਂ ਇਹ flag ਸਮਰੱਥ ਹੋਵੇ, ਤਾਂ RE string ਦੇ ਅੰਦਰ whitespace ਨੂੰ ਅਣਡਿੱਠਾ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਸਿਵਾਏ ਉਸ ਸਥਿਤੀ ਦੇ ਜਦੋਂ whitespace character class ਦੇ ਅੰਦਰ ਹੋਵੇ ਜਾਂ ਕਿਸੇ unescaped backslash ਤੋਂ ਬਾਅਦ ਆਵੇ। ਇਸ ਨਾਲ ਤੁਸੀਂ RE ਨੂੰ ਹੋਰ ਸਪਸ਼ਟ ਢੰਗ ਨਾਲ ਵਿਵਸਥਿਤ ਅਤੇ indent ਕਰ ਸਕਦੇ ਹੋ। ਇਹ flag ਤੁਹਾਨੂੰ RE ਦੇ ਅੰਦਰ comments ਲਿਖਣ ਦੀ ਵੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਜਿਨ੍ਹਾਂ ਨੂੰ engine ਅਣਡਿੱਠਾ ਕਰ ਦਿੰਦਾ ਹੈ; comments ਨੂੰ
'#'ਨਾਲ ਦਰਸਾਇਆ ਜਾਂਦਾ ਹੈ, ਬਸ਼ਰਤੇ ਉਹ character class ਦੇ ਅੰਦਰ ਨਾ ਹੋਣ ਅਤੇ ਨਾ ਹੀ ਕਿਸੇ unescaped backslash ਤੋਂ ਪਹਿਲਾਂ ਹੋਣ।ਉਦਾਹਰਨ ਲਈ, ਇੱਥੇ
re.VERBOSEਦੀ ਵਰਤੋਂ ਕਰਨ ਵਾਲੀ ਇੱਕ RE ਦਿੱਤੀ ਗਈ ਹੈ; ਵੇਖੋ ਇਸਨੂੰ ਪੜ੍ਹਨਾ ਕਿੰਨਾ ਆਸਾਨ ਹੈ।charref = re.compile(r""" &[#] # Start of a numeric entity reference ( 0[0-7]+ # Octal form | [0-9]+ # Decimal form | x[0-9a-fA-F]+ # Hexadecimal form ) ; # Trailing semicolon """, re.VERBOSE)
Verbose setting ਤੋਂ ਬਿਨਾਂ, RE ਇਸ ਤਰ੍ਹਾਂ ਦਿਖਾਈ ਦੇਵੇਗੀ:
charref = re.compile("&#(0[0-7]+" "|[0-9]+" "|x[0-9a-fA-F]+);")
ਉੱਪਰ ਦਿੱਤੀ ਉਦਾਹਰਨ ਵਿੱਚ RE ਨੂੰ ਛੋਟੇ ਭਾਗਾਂ ਵਿੱਚ ਵੰਡਣ ਲਈ Python ਦੀ string literals ਦੀ automatic concatenation ਵਿਸ਼ੇਸ਼ਤਾ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਗਈ ਹੈ, ਪਰ ਫਿਰ ਵੀ ਇਹ
re.VERBOSEਵਾਲੇ ਸੰਸਕਰਣ ਨਾਲੋਂ ਸਮਝਣ ਵਿੱਚ ਵੱਧ ਔਖੀ ਹੈ।
ਪੈਟਰਨਾਂ ਦੀ ਵੱਧ ਤਾਕਤ¶
ਹੁਣ ਤੱਕ ਅਸੀਂ regular expressions ਦੀਆਂ ਕੁਝ ਹੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਬਾਰੇ ਗੱਲ ਕੀਤੀ ਹੈ। ਇਸ ਭਾਗ ਵਿੱਚ ਅਸੀਂ ਕੁਝ ਨਵੇਂ metacharacters ਅਤੇ groups ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਮੈਚ ਕੀਤੇ ਗਏ ਟੈਕਸਟ ਦੇ ਭਾਗਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੇ ਤਰੀਕਿਆਂ ਬਾਰੇ ਸਿੱਖਾਂਗੇ।
ਹੋਰ metacharacters¶
ਕੁਝ metacharacters ਅਜੇ ਵੀ ਬਾਕੀ ਹਨ ਜਿਨ੍ਹਾਂ ਬਾਰੇ ਅਸੀਂ ਹਾਲੇ ਗੱਲ ਨਹੀਂ ਕੀਤੀ। ਉਨ੍ਹਾਂ ਵਿੱਚੋਂ ਜ਼ਿਆਦਾਤਰ ਇਸ ਭਾਗ ਵਿੱਚ ਸਮਝਾਏ ਜਾਣਗੇ।
ਬਾਕੀ ਰਹਿ ਗਏ ਕੁਝ metacharacters zero-width assertions ਹਨ। ਇਹ engine ਨੂੰ ਸਟਰਿੰਗ ਵਿੱਚ ਅੱਗੇ ਨਹੀਂ ਵਧਾਉਂਦੀਆਂ; ਇਸ ਦੀ ਬਜਾਏ, ਇਹ ਕੋਈ ਅੱਖਰ consume ਨਹੀਂ ਕਰਦੀਆਂ ਅਤੇ ਸਿਰਫ਼ ਸਫਲ ਜਾਂ ਅਸਫਲ ਹੁੰਦੀਆਂ ਹਨ। ਉਦਾਹਰਨ ਲਈ, \b ਇੱਕ assertion ਹੈ ਜੋ ਇਹ ਦਰਸਾਉਂਦੀ ਹੈ ਕਿ ਮੌਜੂਦਾ ਸਥਿਤੀ ਸ਼ਬਦ ਸੀਮਾ 'ਤੇ ਹੈ; \b ਖੁਦ ਸਥਿਤੀ ਨੂੰ ਬਿਲਕੁਲ ਨਹੀਂ ਬਦਲਦੀ। ਇਸਦਾ ਅਰਥ ਹੈ ਕਿ zero-width assertions ਨੂੰ ਕਦੇ ਵੀ ਦੁਹਰਾਇਆ ਨਹੀਂ ਜਾਣਾ ਚਾਹੀਦਾ, ਕਿਉਂਕਿ ਜੇ ਇਹ ਇੱਕ ਸਥਾਨ 'ਤੇ ਇੱਕ ਵਾਰ ਮੈਚ ਹੋ ਸਕਦੀਆਂ ਹਨ, ਤਾਂ ਸਿਧਾਂਤਕ ਤੌਰ 'ਤੇ ਇਹ ਅਨੰਤ ਵਾਰ ਮੈਚ ਹੋ ਸਕਦੀਆਂ ਹਨ।
|Alternation, ਜਾਂ "or" operator। ਜੇ A ਅਤੇ B regular expressions ਹਨ, ਤਾਂ
A|Bਕਿਸੇ ਵੀ ਅਜਿਹੀ ਸਟਰਿੰਗ ਨਾਲ ਮੈਚ ਕਰੇਗਾ ਜੋ A ਜਾਂ B ਵਿੱਚੋਂ ਕਿਸੇ ਇੱਕ ਨਾਲ ਮੈਚ ਕਰਦੀ ਹੋਵੇ।|ਦੀ precedence ਬਹੁਤ ਘੱਟ ਹੁੰਦੀ ਹੈ ਤਾਂ ਜੋ ਇਹ ਬਹੁ-ਅੱਖਰੀ ਸਟਰਿੰਗਾਂ ਨਾਲ ਵੀ ਉਚਿਤ ਢੰਗ ਨਾਲ ਕੰਮ ਕਰ ਸਕੇ।Crow|Servoਜਾਂ ਤਾਂ'Crow'ਜਾਂ'Servo'ਨਾਲ ਮੈਚ ਕਰੇਗਾ, ਨਾ ਕਿ'Cro','w','S'ਜਾਂ'ervo'ਨਾਲ।ਇੱਕ literal
'|'ਨਾਲ ਮੈਚ ਕਰਨ ਲਈ\|ਵਰਤੋ, ਜਾਂ ਇਸਨੂੰ character class ਦੇ ਅੰਦਰ ਰੱਖੋ, ਜਿਵੇਂ[|]।^ਲਾਈਨਾਂ ਦੇ ਸ਼ੁਰੂ ਵਿੱਚ ਮੈਚ ਕਰਦਾ ਹੈ। ਜਦ ਤੱਕ
MULTILINEflag ਸੈੱਟ ਨਾ ਕੀਤਾ ਗਿਆ ਹੋਵੇ, ਇਹ ਸਿਰਫ਼ ਸਟਰਿੰਗ ਦੇ ਸ਼ੁਰੂ ਵਿੱਚ ਹੀ ਮੈਚ ਕਰੇਗਾ।MULTILINEmode ਵਿੱਚ ਇਹ ਸਟਰਿੰਗ ਦੇ ਅੰਦਰ ਹਰ newline ਤੋਂ ਤੁਰੰਤ ਬਾਅਦ ਵੀ ਮੈਚ ਕਰਦਾ ਹੈ।ਉਦਾਹਰਨ ਲਈ, ਜੇ ਤੁਸੀਂ ਸ਼ਬਦ
Fromਨਾਲ ਸਿਰਫ਼ ਲਾਈਨ ਦੇ ਸ਼ੁਰੂ ਵਿੱਚ ਮੈਚ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ ਵਰਤੀ ਜਾਣ ਵਾਲੀ RE^Fromਹੋਵੇਗੀ।>>> print(re.search('^From', 'From Here to Eternity')) <re.Match object; span=(0, 4), match='From'> >>> print(re.search('^From', 'Reciting From Memory')) None
ਇੱਕ literal
'^'ਨਾਲ ਮੈਚ ਕਰਨ ਲਈ\^ਵਰਤੋ।$ਲਾਈਨ ਦੇ ਅੰਤ 'ਤੇ ਮੈਚ ਕਰਦਾ ਹੈ, ਜਿਸਦਾ ਅਰਥ ਜਾਂ ਤਾਂ ਸਟਰਿੰਗ ਦਾ ਅੰਤ ਹੁੰਦਾ ਹੈ ਜਾਂ ਕੋਈ ਅਜਿਹੀ ਸਥਿਤੀ ਜਿਸ ਤੋਂ ਤੁਰੰਤ ਬਾਅਦ newline ਅੱਖਰ ਆਉਂਦਾ ਹੋਵੇ।
>>> print(re.search('}$', '{block}')) <re.Match object; span=(6, 7), match='}'> >>> print(re.search('}$', '{block} ')) None >>> print(re.search('}$', '{block}\n')) <re.Match object; span=(6, 7), match='}'>
ਇੱਕ literal
'$'ਨਾਲ ਮੈਚ ਕਰਨ ਲਈ\$ਵਰਤੋ ਜਾਂ ਇਸਨੂੰ character class ਦੇ ਅੰਦਰ ਰੱਖੋ, ਜਿਵੇਂ[$]।\Aਸਿਰਫ਼ ਸਟਰਿੰਗ ਦੇ ਸ਼ੁਰੂ ਵਿੱਚ ਮੈਚ ਕਰਦਾ ਹੈ। ਜਦੋਂ
MULTILINEmode ਸਰਗਰਮ ਨਾ ਹੋਵੇ, ਤਾਂ\Aਅਤੇ^ਅਸਲ ਵਿੱਚ ਇੱਕੋ ਜਿਹੇ ਹੁੰਦੇ ਹਨ।MULTILINEmode ਵਿੱਚ ਇਹ ਵੱਖਰੇ ਹਨ:\Aਫਿਰ ਵੀ ਸਿਰਫ਼ ਸਟਰਿੰਗ ਦੇ ਸ਼ੁਰੂ ਵਿੱਚ ਹੀ ਮੈਚ ਕਰਦਾ ਹੈ, ਜਦਕਿ^ਸਟਰਿੰਗ ਦੇ ਅੰਦਰ newline ਤੋਂ ਬਾਅਦ ਆਉਣ ਵਾਲੀਆਂ ਹੋਰ ਸਥਿਤੀਆਂ ਨਾਲ ਵੀ ਮੈਚ ਕਰ ਸਕਦਾ ਹੈ।\zਸਿਰਫ਼ ਸਟਰਿੰਗ ਦੇ ਅੰਤ ਵਿੱਚ ਮੈਚ ਕਰਦਾ ਹੈ।
\Z\zਦੇ ਸਮਾਨ ਹੈ। ਪੁਰਾਣੇ Python ਸੰਸਕਰਣਾਂ ਨਾਲ ਅਨੁਕੂਲਤਾ ਲਈ ਉਪਲਬਧ ਹੈ।\bਸ਼ਬਦ ਸੀਮਾ। ਇਹ ਇੱਕ zero-width assertion ਹੈ ਜੋ ਸਿਰਫ਼ ਕਿਸੇ ਸ਼ਬਦ ਦੇ ਸ਼ੁਰੂ ਜਾਂ ਅੰਤ 'ਤੇ ਮੈਚ ਕਰਦੀ ਹੈ। ਇੱਕ ਸ਼ਬਦ ਨੂੰ ਅੱਖਰ-ਅੰਕ ਅੱਖਰਾਂ ਦੀ ਲੜੀ ਵਜੋਂ ਪਰਿਭਾਸ਼ਿਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਇਸ ਲਈ ਸ਼ਬਦ ਦਾ ਅੰਤ whitespace ਜਾਂ ਕਿਸੇ non-alphanumeric ਅੱਖਰ ਦੁਆਰਾ ਦਰਸਾਇਆ ਜਾਂਦਾ ਹੈ।
ਹੇਠਾਂ ਦਿੱਤੀ ਉਦਾਹਰਨ
classਨਾਲ ਸਿਰਫ਼ ਤਦ ਮੈਚ ਕਰਦੀ ਹੈ ਜਦੋਂ ਇਹ ਇੱਕ ਪੂਰਾ ਸ਼ਬਦ ਹੋਵੇ; ਜਦੋਂ ਇਹ ਕਿਸੇ ਹੋਰ ਸ਼ਬਦ ਦੇ ਅੰਦਰ ਹੋਵੇ ਤਾਂ ਮੈਚ ਨਹੀਂ ਕਰੇਗੀ।>>> p = re.compile(r'\bclass\b') >>> print(p.search('no class at all')) <re.Match object; span=(3, 8), match='class'> >>> print(p.search('the declassified algorithm')) None >>> print(p.search('one subclass is')) None
ਇਸ special sequence ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ ਦੋ ਸੁਖਮ ਗੱਲਾਂ ਯਾਦ ਰੱਖਣੀਆਂ ਚਾਹੀਦੀਆਂ ਹਨ। ਪਹਿਲੀ ਗੱਲ ਇਹ ਹੈ ਕਿ ਇਹ Python string literals ਅਤੇ regular expression sequences ਵਿਚਕਾਰ ਸਭ ਤੋਂ ਵੱਡੀ ਟਕਰਾਅ ਵਾਲੀ ਸਥਿਤੀ ਹੈ। Python string literals ਵਿੱਚ
\bbackspace ਅੱਖਰ ਹੁੰਦਾ ਹੈ, ਜਿਸਦੀ ASCII value 8 ਹੈ। ਜੇ ਤੁਸੀਂ raw strings ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਰਹੇ, ਤਾਂ Python\bਨੂੰ backspace ਵਿੱਚ ਬਦਲ ਦੇਵੇਗਾ ਅਤੇ ਤੁਹਾਡੀ RE ਉਮੀਦ ਅਨੁਸਾਰ ਮੈਚ ਨਹੀਂ ਕਰੇਗੀ। ਹੇਠਾਂ ਦਿੱਤੀ ਉਦਾਹਰਨ ਸਾਡੀ ਪਿਛਲੀ RE ਵਰਗੀ ਹੀ ਦਿਖਾਈ ਦਿੰਦੀ ਹੈ, ਪਰ ਇਸ ਵਿੱਚ RE string ਤੋਂ ਪਹਿਲਾਂ'r'ਨਹੀਂ ਹੈ।>>> p = re.compile('\bclass\b') >>> print(p.search('no class at all')) None >>> print(p.search('\b' + 'class' + '\b')) <re.Match object; span=(0, 7), match='\x08class\x08'>
ਦੂਜੀ ਗੱਲ, character class ਦੇ ਅੰਦਰ, ਜਿੱਥੇ ਇਸ assertion ਦੀ ਕੋਈ ਵਰਤੋਂ ਨਹੀਂ ਹੁੰਦੀ,
\bcompatibility ਲਈ backspace ਅੱਖਰ ਨੂੰ ਦਰਸਾਉਂਦਾ ਹੈ।\Bਇੱਕ ਹੋਰ zero-width assertion। ਇਹ
\bਦੇ ਉਲਟ ਹੈ ਅਤੇ ਸਿਰਫ਼ ਉਸ ਵੇਲੇ ਮੈਚ ਕਰਦੀ ਹੈ ਜਦੋਂ ਮੌਜੂਦਾ ਸਥਿਤੀ ਕਿਸੇ word boundary 'ਤੇ ਨਾ ਹੋਵੇ।
ਗਰੂਪਿੰਗ¶
ਅਕਸਰ ਤੁਹਾਨੂੰ ਸਿਰਫ਼ ਇਹ ਜਾਣਨ ਨਾਲੋਂ ਵੱਧ ਜਾਣਕਾਰੀ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ ਕਿ RE ਮੈਚ ਹੋਈ ਜਾਂ ਨਹੀਂ। Regular expressions ਦੀ ਵਰਤੋਂ ਅਕਸਰ ਸਟਰਿੰਗਾਂ ਨੂੰ ਵੱਖ-ਵੱਖ ਹਿੱਸਿਆਂ ਵਿੱਚ ਤੋੜਨ ਲਈ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਜਿਸ ਲਈ ਇੱਕ ਅਜਿਹੀ RE ਲਿਖੀ ਜਾਂਦੀ ਹੈ ਜੋ ਕਈ subgroups ਵਿੱਚ ਵੰਡੀ ਹੋਈ ਹੋਵੇ ਅਤੇ ਹਰ subgroup ਦਿਲਚਸਪੀ ਵਾਲੇ ਵੱਖਰੇ ਭਾਗ ਨਾਲ ਮੈਚ ਕਰੇ। ਉਦਾਹਰਨ ਲਈ, ਇੱਕ RFC-822 header line ਨੂੰ header name ਅਤੇ value ਵਿੱਚ ਵੰਡਿਆ ਜਾਂਦਾ ਹੈ, ਜਿਨ੍ਹਾਂ ਨੂੰ ':' ਵੱਖ ਕਰਦਾ ਹੈ:
From: author@example.com
User-Agent: Thunderbird 1.5.0.9 (X11/20061227)
MIME-Version: 1.0
To: editor@example.com
ਇਸਨੂੰ ਇੱਕ ਅਜਿਹੀ regular expression ਲਿਖ ਕੇ ਸੰਭਾਲਿਆ ਜਾ ਸਕਦਾ ਹੈ ਜੋ ਪੂਰੀ header line ਨਾਲ ਮੈਚ ਕਰੇ ਅਤੇ ਜਿਸ ਵਿੱਚ ਇੱਕ group header name ਨਾਲ ਅਤੇ ਦੂਜਾ group header value ਨਾਲ ਮੈਚ ਕਰੇ।
Groups ਨੂੰ '(' ਅਤੇ ')' metacharacters ਦੁਆਰਾ ਦਰਸਾਇਆ ਜਾਂਦਾ ਹੈ। '(' ਅਤੇ ')' ਦਾ ਅਰਥ ਲਗਭਗ ਉਹੀ ਹੁੰਦਾ ਹੈ ਜੋ ਗਣਿਤੀ expressions ਵਿੱਚ ਹੁੰਦਾ ਹੈ; ਇਹ ਆਪਣੇ ਅੰਦਰ ਮੌਜੂਦ expressions ਨੂੰ ਇਕੱਠਾ ਗਰੂਪ ਕਰਦੇ ਹਨ ਅਤੇ ਤੁਸੀਂ ਕਿਸੇ group ਦੀ ਸਮੱਗਰੀ ਨੂੰ *, +, ? ਜਾਂ {m,n} ਵਰਗੇ quantifier ਨਾਲ ਦੁਹਰਾ ਸਕਦੇ ਹੋ। ਉਦਾਹਰਨ ਲਈ, (ab)* ab ਦੀਆਂ ਸ਼ੂਨ੍ਯ ਜਾਂ ਵੱਧ ਦੁਹਰਾਵਾਂ ਨਾਲ ਮੈਚ ਕਰੇਗਾ।
>>> p = re.compile('(ab)*')
>>> print(p.search('ababababab').span())
(0, 10)
'(' ਅਤੇ ')' ਨਾਲ ਦਰਸਾਏ ਗਏ groups ਉਸ ਟੈਕਸਟ ਦੇ ਸ਼ੁਰੂ ਅਤੇ ਅੰਤ ਦੇ index ਵੀ capture ਕਰਦੇ ਹਨ ਜਿਸ ਨਾਲ ਉਹ ਮੈਚ ਕਰਦੇ ਹਨ; ਇਹ ਜਾਣਕਾਰੀ group(), start(), end() ਅਤੇ span() ਨੂੰ argument ਦੇ ਕੇ ਪ੍ਰਾਪਤ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ। Groups ਦੀ ਗਿਣਤੀ 0 ਤੋਂ ਸ਼ੁਰੂ ਹੁੰਦੀ ਹੈ। Group 0 ਹਮੇਸ਼ਾਂ ਮੌਜੂਦ ਹੁੰਦਾ ਹੈ; ਇਹ ਪੂਰੀ RE ਨੂੰ ਦਰਸਾਉਂਦਾ ਹੈ, ਇਸ ਲਈ match object methods ਵਿੱਚ group 0 ਮੂਲ argument ਹੁੰਦਾ ਹੈ। ਅੱਗੇ ਅਸੀਂ ਵੇਖਾਂਗੇ ਕਿ ਅਜਿਹੇ groups ਕਿਵੇਂ ਬਣਾਏ ਜਾਂਦੇ ਹਨ ਜੋ ਆਪਣੇ ਮੈਚ ਕੀਤੇ ਟੈਕਸਟ ਦੀ span capture ਨਹੀਂ ਕਰਦੇ।
>>> p = re.compile('(a)b')
>>> m = p.search('ab')
>>> m.group()
'ab'
>>> m.group(0)
'ab'
Subgroups ਨੂੰ ਖੱਬੇ ਤੋਂ ਸੱਜੇ ਕ੍ਰਮ ਵਿੱਚ 1 ਤੋਂ ਸ਼ੁਰੂ ਕਰਕੇ ਨੰਬਰ ਦਿੱਤੇ ਜਾਂਦੇ ਹਨ। Groups nested ਵੀ ਹੋ ਸਕਦੇ ਹਨ; group number ਪਤਾ ਕਰਨ ਲਈ ਸਿਰਫ਼ opening parenthesis ਅੱਖਰਾਂ ਨੂੰ ਖੱਬੇ ਤੋਂ ਸੱਜੇ ਗਿਣੋ।
>>> p = re.compile('(a(b)c)d')
>>> m = p.search('abcd')
>>> m.group(0)
'abcd'
>>> m.group(1)
'abc'
>>> m.group(2)
'b'
group() ਨੂੰ ਇੱਕੋ ਸਮੇਂ ਕਈ group numbers ਦਿੱਤੇ ਜਾ ਸਕਦੇ ਹਨ, ਜਿਸ ਸਥਿਤੀ ਵਿੱਚ ਇਹ ਉਹਨਾਂ groups ਦੇ ਸੰਬੰਧਿਤ ਮੁੱਲਾਂ ਵਾਲਾ ਇੱਕ tuple ਵਾਪਸ ਕਰਦਾ ਹੈ।
>>> m.group(2,1,2)
('b', 'abc', 'b')
groups() method 1 ਤੋਂ ਲੈ ਕੇ ਸਾਰੇ subgroups ਦੀਆਂ strings ਵਾਲਾ ਇੱਕ tuple ਵਾਪਸ ਕਰਦੀ ਹੈ।
>>> m.groups()
('abc', 'b')
Pattern ਵਿੱਚ backreferences ਤੁਹਾਨੂੰ ਇਹ ਨਿਰਧਾਰਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀਆਂ ਹਨ ਕਿ ਪਹਿਲਾਂ capture ਕੀਤੇ ਗਏ group ਦੀ ਸਮੱਗਰੀ ਮੌਜੂਦਾ ਸਥਿਤੀ 'ਤੇ ਵੀ ਮਿਲਣੀ ਚਾਹੀਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, \1 ਤਦ ਸਫਲ ਹੋਵੇਗਾ ਜੇ group 1 ਦੀ ਠੀਕ ਸਮੱਗਰੀ ਮੌਜੂਦਾ ਸਥਿਤੀ 'ਤੇ ਮਿਲ ਜਾਵੇ; ਨਹੀਂ ਤਾਂ ਇਹ ਅਸਫਲ ਹੋ ਜਾਵੇਗਾ। ਯਾਦ ਰੱਖੋ ਕਿ Python string literals ਵੀ backslash ਤੋਂ ਬਾਅਦ ਨੰਬਰਾਂ ਦੀ ਵਰਤੋਂ ਕਰਕੇ arbitrary characters ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀਆਂ ਹਨ, ਇਸ ਲਈ RE ਵਿੱਚ backreferences ਵਰਤਦੇ ਸਮੇਂ raw string ਦੀ ਵਰਤੋਂ ਕਰਨਾ ਯਕੀਨੀ ਬਣਾਓ।
ਉਦਾਹਰਨ ਲਈ, ਹੇਠਾਂ ਦਿੱਤੀ RE ਇੱਕ ਸਟਰਿੰਗ ਵਿੱਚ ਦੁਹਰਾਏ ਹੋਏ ਸ਼ਬਦਾਂ ਨੂੰ ਖੋਜਦੀ ਹੈ।
>>> p = re.compile(r'\b(\w+)\s+\1\b')
>>> p.search('Paris in the the spring').group()
'the the'
ਇਸ ਤਰ੍ਹਾਂ ਦੀਆਂ backreferences ਸਿਰਫ਼ ਸਟਰਿੰਗ ਵਿੱਚ ਖੋਜ ਕਰਨ ਲਈ ਬਹੁਤ ਵਾਰ ਲਾਭਦਾਇਕ ਨਹੀਂ ਹੁੰਦੀਆਂ — ਕਿਉਂਕਿ ਬਹੁਤ ਘੱਟ text formats ਇਸ ਤਰੀਕੇ ਨਾਲ ਡਾਟਾ ਦੁਹਰਾਉਂਦੀਆਂ ਹਨ — ਪਰ ਤੁਸੀਂ ਜਲਦੀ ਹੀ ਵੇਖੋਗੇ ਕਿ string substitutions ਕਰਦੇ ਸਮੇਂ ਇਹ ਬਹੁਤ ਲਾਭਦਾਇਕ ਹੁੰਦੀਆਂ ਹਨ।
Non-capturing ਅਤੇ named groups¶
ਜਟਿਲ REs ਵਿੱਚ ਅਕਸਰ ਬਹੁਤ ਸਾਰੇ groups ਵਰਤੇ ਜਾਂਦੇ ਹਨ, ਕੁਝ ਦਿਲਚਸਪੀ ਵਾਲੀਆਂ substrings ਨੂੰ capture ਕਰਨ ਲਈ ਅਤੇ ਕੁਝ RE ਨੂੰ ਖੁਦ ਗਰੂਪ ਅਤੇ ਸੰਰਚਿਤ ਕਰਨ ਲਈ। ਜਟਿਲ REs ਵਿੱਚ group numbers ਨੂੰ ਯਾਦ ਰੱਖਣਾ ਮੁਸ਼ਕਲ ਹੋ ਜਾਂਦਾ ਹੈ। ਇਸ ਸਮੱਸਿਆ ਨੂੰ ਹੱਲ ਕਰਨ ਲਈ ਦੋ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਹਨ। ਦੋਵੇਂ regular expression extensions ਲਈ ਇੱਕ ਸਾਂਝਾ syntax ਵਰਤਦੀਆਂ ਹਨ, ਇਸ ਲਈ ਪਹਿਲਾਂ ਅਸੀਂ ਉਸਨੂੰ ਵੇਖਾਂਗੇ।
Perl 5 ਆਪਣੀਆਂ ਸ਼ਕਤੀਸ਼ਾਲੀ regular expression extensions ਲਈ ਮਸ਼ਹੂਰ ਹੈ। ਇਨ੍ਹਾਂ ਨਵੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਲਈ Perl developers ਨਵੇਂ single-keystroke metacharacters ਜਾਂ \ ਨਾਲ ਸ਼ੁਰੂ ਹੋਣ ਵਾਲੀਆਂ ਨਵੀਆਂ special sequences ਨਹੀਂ ਚੁਣ ਸਕਦੇ ਸਨ, ਕਿਉਂਕਿ ਇਸ ਨਾਲ Perl ਦੀਆਂ regular expressions ਮਿਆਰੀ REs ਨਾਲੋਂ ਬਹੁਤ ਵੱਖਰੀਆਂ ਅਤੇ ਉਲਝਣਭਰੀਆਂ ਹੋ ਜਾਂਦੀਆਂ। ਉਦਾਹਰਨ ਲਈ, ਜੇ & ਨੂੰ ਇੱਕ ਨਵੇਂ metacharacter ਵਜੋਂ ਚੁਣਦੇ, ਤਾਂ ਪੁਰਾਣੀਆਂ expressions ਇਹ ਮੰਨ ਕੇ ਚੱਲਦੀਆਂ ਕਿ & ਇੱਕ ਆਮ ਅੱਖਰ ਹੈ ਅਤੇ ਉਸਨੂੰ \& ਜਾਂ [&] ਵਜੋਂ escape ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੋਵੇਗਾ।
Perl developers ਦੁਆਰਾ ਚੁਣਿਆ ਗਿਆ ਹੱਲ (?...) extension syntax ਸੀ। Parenthesis ਤੋਂ ਤੁਰੰਤ ਬਾਅਦ ਆਉਣ ਵਾਲਾ ? ਇੱਕ syntax error ਹੁੰਦਾ, ਕਿਉਂਕਿ ? ਕੋਲ ਦੁਹਰਾਉਣ ਲਈ ਕੁਝ ਨਹੀਂ ਹੁੰਦਾ, ਇਸ ਲਈ ਇਸ ਨਾਲ compatibility ਦੀ ਕੋਈ ਸਮੱਸਿਆ ਪੈਦਾ ਨਹੀਂ ਹੋਈ। ? ਤੋਂ ਤੁਰੰਤ ਬਾਅਦ ਆਉਣ ਵਾਲੇ ਅੱਖਰ ਦਰਸਾਉਂਦੇ ਹਨ ਕਿ ਕਿਹੜੀ extension ਵਰਤੀ ਜਾ ਰਹੀ ਹੈ; ਇਸ ਲਈ (?=foo) ਇੱਕ ਚੀਜ਼ ਹੈ (positive lookahead assertion) ਅਤੇ (?:foo) ਕੁਝ ਹੋਰ ਹੈ (subexpression foo ਵਾਲਾ non-capturing group)।
Python Perl ਦੀਆਂ ਕਈ extensions ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ ਅਤੇ Perl ਦੀ extension syntax ਵਿੱਚ ਆਪਣੀਆਂ extensions ਵੀ ਜੋੜਦਾ ਹੈ। ਜੇ question mark ਤੋਂ ਬਾਅਦ ਪਹਿਲਾ ਅੱਖਰ P ਹੋਵੇ, ਤਾਂ ਤੁਸੀਂ ਜਾਣ ਸਕਦੇ ਹੋ ਕਿ ਇਹ Python-ਵਿਸ਼ੇਸ਼ extension ਹੈ।
ਹੁਣ ਜਦੋਂ ਅਸੀਂ ਆਮ extension syntax ਨੂੰ ਵੇਖ ਲਿਆ ਹੈ, ਅਸੀਂ ਉਹਨਾਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਵੱਲ ਵਾਪਸ ਆ ਸਕਦੇ ਹਾਂ ਜੋ ਜਟਿਲ REs ਵਿੱਚ groups ਨਾਲ ਕੰਮ ਕਰਨਾ ਆਸਾਨ ਬਣਾਉਂਦੀਆਂ ਹਨ।
ਕਈ ਵਾਰ ਤੁਸੀਂ regular expression ਦੇ ਕਿਸੇ ਹਿੱਸੇ ਨੂੰ ਦਰਸਾਉਣ ਲਈ group ਵਰਤਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਪਰ ਉਸ group ਦੀ ਸਮੱਗਰੀ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਦਿਲਚਸਪੀ ਨਹੀਂ ਹੁੰਦੀ। ਤੁਸੀਂ ਇਸ ਗੱਲ ਨੂੰ non-capturing group ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਸਪਸ਼ਟ ਕਰ ਸਕਦੇ ਹੋ: (?:...)। ਇੱਥੇ ... ਦੀ ਥਾਂ ਕੋਈ ਵੀ regular expression ਰੱਖੀ ਜਾ ਸਕਦੀ ਹੈ।
>>> m = re.search("([abc])+", "abc")
>>> m.groups()
('c',)
>>> m = re.search("(?:[abc])+", "abc")
>>> m.groups()
()
ਇਸ ਗੱਲ ਤੋਂ ਇਲਾਵਾ ਕਿ ਤੁਸੀਂ group ਦੁਆਰਾ ਮੈਚ ਕੀਤੀ ਸਮੱਗਰੀ ਨੂੰ ਪ੍ਰਾਪਤ ਨਹੀਂ ਕਰ ਸਕਦੇ, non-capturing group ਬਿਲਕੁਲ capturing group ਵਾਂਗ ਹੀ ਵਰਤਾਓ ਕਰਦਾ ਹੈ; ਤੁਸੀਂ ਇਸਦੇ ਅੰਦਰ ਕੁਝ ਵੀ ਰੱਖ ਸਕਦੇ ਹੋ, ਇਸਨੂੰ * ਵਰਗੇ repetition metacharacter ਨਾਲ ਦੁਹਰਾ ਸਕਦੇ ਹੋ ਅਤੇ ਇਸਨੂੰ ਹੋਰ groups (capturing ਜਾਂ non-capturing) ਦੇ ਅੰਦਰ nest ਵੀ ਕਰ ਸਕਦੇ ਹੋ। (?:...) ਮੌਜੂਦਾ pattern ਵਿੱਚ ਸੋਧ ਕਰਦੇ ਸਮੇਂ ਖਾਸ ਤੌਰ 'ਤੇ ਲਾਭਦਾਇਕ ਹੁੰਦਾ ਹੈ, ਕਿਉਂਕਿ ਤੁਸੀਂ ਹੋਰ groups ਦੀ numbering ਬਦਲੇ ਬਿਨਾਂ ਨਵੇਂ groups ਜੋੜ ਸਕਦੇ ਹੋ। ਇਹ ਵੀ ਧਿਆਨਯੋਗ ਹੈ ਕਿ capturing ਅਤੇ non-capturing groups ਵਿੱਚ searching performance ਦਾ ਕੋਈ ਅੰਤਰ ਨਹੀਂ ਹੁੰਦਾ; ਕੋਈ ਵੀ ਦੂਜੇ ਨਾਲੋਂ ਤੇਜ਼ ਨਹੀਂ ਹੈ।
ਇੱਕ ਹੋਰ ਮਹੱਤਵਪੂਰਨ ਵਿਸ਼ੇਸ਼ਤਾ named groups ਹਨ: groups ਨੂੰ ਨੰਬਰਾਂ ਦੀ ਬਜਾਏ ਨਾਂ ਦੁਆਰਾ ਵੀ ਦਰਸਾਇਆ ਜਾ ਸਕਦਾ ਹੈ।
Named group ਦਾ syntax Python-ਵਿਸ਼ੇਸ਼ extensions ਵਿੱਚੋਂ ਇੱਕ ਹੈ: (?P<name>...)। name ਸਪਸ਼ਟ ਤੌਰ 'ਤੇ group ਦਾ ਨਾਮ ਹੈ। Named groups ਬਿਲਕੁਲ capturing groups ਵਾਂਗ ਹੀ ਵਰਤਾਓ ਕਰਦੇ ਹਨ ਅਤੇ ਨਾਲ ਹੀ group ਨਾਲ ਇੱਕ ਨਾਮ ਵੀ ਜੋੜਦੇ ਹਨ। match object ਦੀਆਂ ਉਹ methods ਜੋ capturing groups ਨਾਲ ਕੰਮ ਕਰਦੀਆਂ ਹਨ, group number ਦਰਸਾਉਣ ਲਈ integer ਜਾਂ group name ਵਾਲੀ string ਦੋਵੇਂ ਸਵੀਕਾਰ ਕਰਦੀਆਂ ਹਨ। Named groups ਨੂੰ ਫਿਰ ਵੀ ਨੰਬਰ ਦਿੱਤੇ ਜਾਂਦੇ ਹਨ, ਇਸ ਲਈ ਤੁਸੀਂ group ਦੀ ਜਾਣਕਾਰੀ ਦੋ ਤਰੀਕਿਆਂ ਨਾਲ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੇ ਹੋ:
>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search('(((( Lots of punctuation )))')
>>> m.group('word')
'Lots'
>>> m.group(1)
'Lots'
ਇਸ ਤੋਂ ਇਲਾਵਾ, ਤੁਸੀਂ groupdict() ਦੀ ਵਰਤੋਂ ਕਰਕੇ named groups ਨੂੰ ਇੱਕ dictionary ਵਜੋਂ ਵੀ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੇ ਹੋ:
>>> m = re.search(r'(?P<first>\w+) (?P<last>\w+)', 'Jane Doe')
>>> m.groupdict()
{'first': 'Jane', 'last': 'Doe'}
Named groups ਲਾਭਦਾਇਕ ਹੁੰਦੇ ਹਨ ਕਿਉਂਕਿ ਇਹ ਤੁਹਾਨੂੰ ਨੰਬਰਾਂ ਨੂੰ ਯਾਦ ਰੱਖਣ ਦੀ ਬਜਾਏ ਆਸਾਨੀ ਨਾਲ ਯਾਦ ਰਹਿ ਜਾਣ ਵਾਲੇ ਨਾਮ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੰਦੇ ਹਨ। ਇੱਥੇ imaplib ਮੋਡੀਊਲ ਤੋਂ ਇੱਕ ਉਦਾਹਰਨ RE ਦਿੱਤੀ ਗਈ ਹੈ:
InternalDate = re.compile(r'INTERNALDATE "'
r'(?P<day>[ 123][0-9])-(?P<mon>[A-Z][a-z][a-z])-'
r'(?P<year>[0-9][0-9][0-9][0-9])'
r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'
r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])'
r'"')
ਸਪਸ਼ਟ ਹੈ ਕਿ group 9 ਨੂੰ ਯਾਦ ਰੱਖਣ ਦੀ ਬਜਾਏ m.group('zonem') ਲਿਖਣਾ ਕਾਫ਼ੀ ਆਸਾਨ ਹੈ।
(...)\1 ਵਰਗੀ expression ਵਿੱਚ backreferences ਦਾ syntax group number ਨੂੰ ਦਰਸਾਉਂਦਾ ਹੈ। ਕੁਦਰਤੀ ਤੌਰ 'ਤੇ ਇਸਦਾ ਇੱਕ ਰੂਪ ਅਜਿਹਾ ਵੀ ਹੈ ਜੋ number ਦੀ ਬਜਾਏ group name ਵਰਤਦਾ ਹੈ। ਇਹ ਵੀ ਇੱਕ Python extension ਹੈ: (?P=name) ਦਰਸਾਉਂਦਾ ਹੈ ਕਿ name ਨਾਮਕ group ਦੀ ਸਮੱਗਰੀ ਮੌਜੂਦਾ ਸਥਾਨ 'ਤੇ ਦੁਬਾਰਾ ਮੈਚ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ। Doubled words ਖੋਜਣ ਵਾਲੀ regular expression \b(\w+)\s+\1\b ਨੂੰ \b(?P<word>\w+)\s+(?P=word)\b ਵਜੋਂ ਵੀ ਲਿਖਿਆ ਜਾ ਸਕਦਾ ਹੈ:
>>> p = re.compile(r'\b(?P<word>\w+)\s+(?P=word)\b')
>>> p.search('Paris in the the spring').group()
'the the'
Lookahead assertions¶
ਇੱਕ ਹੋਰ zero-width assertion lookahead assertion ਹੈ। Lookahead assertions positive ਅਤੇ negative ਦੋਹਾਂ ਰੂਪਾਂ ਵਿੱਚ ਉਪਲਬਧ ਹਨ ਅਤੇ ਇਹ ਇਸ ਤਰ੍ਹਾਂ ਦਿਖਦੀਆਂ ਹਨ:
(?=...)Positive lookahead assertion। ਜੇ ਇੱਥੇ
...ਦੁਆਰਾ ਦਰਸਾਈ ਗਈ regular expression ਮੌਜੂਦਾ ਸਥਿਤੀ 'ਤੇ ਸਫਲਤਾਪੂਰਵਕ ਮੈਚ ਕਰ ਜਾਂਦੀ ਹੈ, ਤਾਂ ਇਹ assertion ਸਫਲ ਹੋ ਜਾਂਦੀ ਹੈ; ਨਹੀਂ ਤਾਂ ਅਸਫਲ। ਪਰ contained expression ਦੀ ਜਾਂਚ ਹੋ ਜਾਣ ਤੋਂ ਬਾਅਦ matching engine ਬਿਲਕੁਲ ਵੀ ਅੱਗੇ ਨਹੀਂ ਵਧਦਾ; pattern ਦਾ ਬਾਕੀ ਹਿੱਸਾ ਓਥੇ ਹੀ ਅਜ਼ਮਾਇਆ ਜਾਂਦਾ ਹੈ ਜਿੱਥੋਂ assertion ਸ਼ੁਰੂ ਹੋਈ ਸੀ।(?!...)Negative lookahead assertion। ਇਹ positive assertion ਦਾ ਉਲਟ ਹੈ; ਜੇ contained expression ਸਟਰਿੰਗ ਦੀ ਮੌਜੂਦਾ ਸਥਿਤੀ 'ਤੇ ਮੈਚ ਨਾ ਕਰੇ, ਤਾਂ ਇਹ ਸਫਲ ਹੋ ਜਾਂਦੀ ਹੈ।
ਇਸਨੂੰ ਹੋਰ ਸਪਸ਼ਟ ਬਣਾਉਣ ਲਈ ਆਓ ਇੱਕ ਅਜਿਹਾ ਮਾਮਲਾ ਵੇਖੀਏ ਜਿੱਥੇ lookahead ਲਾਭਦਾਇਕ ਹੁੰਦੀ ਹੈ। ਮੰਨੋ ਤੁਸੀਂ ਇੱਕ filename ਨਾਲ ਮੈਚ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ ਅਤੇ ਉਸਨੂੰ base name ਅਤੇ extension ਵਿੱਚ ਵੰਡਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਜਿਨ੍ਹਾਂ ਨੂੰ . ਵੱਖ ਕਰਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, news.rc ਵਿੱਚ news base name ਹੈ ਅਤੇ rc filename ਦੀ extension ਹੈ।
ਇਸ ਨਾਲ ਮੈਚ ਕਰਨ ਲਈ pattern ਕਾਫ਼ੀ ਸਧਾਰਣ ਹੈ:
.*[.].*$
ਧਿਆਨ ਦਿਓ ਕਿ . ਨੂੰ ਖਾਸ ਤਰੀਕੇ ਨਾਲ ਸੰਭਾਲਣਾ ਪੈਂਦਾ ਹੈ ਕਿਉਂਕਿ ਇਹ ਇੱਕ metacharacter ਹੈ, ਇਸ ਲਈ ਇਸਨੂੰ character class ਦੇ ਅੰਦਰ ਰੱਖਿਆ ਗਿਆ ਹੈ ਤਾਂ ਜੋ ਇਹ ਸਿਰਫ਼ ਉਸ ਖਾਸ ਅੱਖਰ ਨਾਲ ਹੀ ਮੈਚ ਕਰੇ। ਨਾਲ ਹੀ, ਅੰਤ ਵਿੱਚ ਲਗਿਆ $ ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਸਟਰਿੰਗ ਦਾ ਬਾਕੀ ਸਾਰਾ ਹਿੱਸਾ extension ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਵੇ। ਇਹ regular expression foo.bar, autoexec.bat, sendmail.cf ਅਤੇ printers.conf ਨਾਲ ਮੈਚ ਕਰਦੀ ਹੈ।
ਹੁਣ ਸਮੱਸਿਆ ਨੂੰ ਥੋੜ੍ਹਾ ਜਟਿਲ ਬਣਾਈਏ; ਜੇ ਤੁਸੀਂ ਅਜਿਹੇ filenames ਨਾਲ ਮੈਚ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ ਜਿਨ੍ਹਾਂ ਦੀ extension bat ਨਾ ਹੋਵੇ ਤਾਂ ਕੀ ਕਰੋਂਗੇ? ਕੁਝ ਗਲਤ ਕੋਸ਼ਿਸ਼ਾਂ:
.*[.][^b].*$
ਉੱਪਰ ਦਿੱਤੀ ਪਹਿਲੀ ਕੋਸ਼ਿਸ਼ bat ਨੂੰ ਬਾਹਰ ਰੱਖਣ ਲਈ ਇਹ ਸ਼ਰਤ ਲਗਾਉਂਦੀ ਹੈ ਕਿ extension ਦਾ ਪਹਿਲਾ ਅੱਖਰ b ਨਾ ਹੋਵੇ। ਇਹ ਗਲਤ ਹੈ, ਕਿਉਂਕਿ ਇਸ pattern ਨਾਲ foo.bar ਵੀ ਮੈਚ ਨਹੀਂ ਕਰੇਗੀ।
.*[.]([^b]..|.[^a].|..[^t])$
ਜਦੋਂ ਤੁਸੀਂ ਪਹਿਲੇ ਹੱਲ ਨੂੰ ਠੀਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਹੋ ਅਤੇ ਇਹ ਸ਼ਰਤ ਲਗਾਉਂਦੇ ਹੋ ਕਿ ਹੇਠਾਂ ਦਿੱਤੀਆਂ ਵਿੱਚੋਂ ਕੋਈ ਇੱਕ ਸਥਿਤੀ ਮੈਚ ਹੋਵੇ — extension ਦਾ ਪਹਿਲਾ ਅੱਖਰ b ਨਾ ਹੋਵੇ, ਜਾਂ ਦੂਜਾ ਅੱਖਰ a ਨਾ ਹੋਵੇ, ਜਾਂ ਤੀਜਾ ਅੱਖਰ t ਨਾ ਹੋਵੇ — ਤਾਂ expression ਹੋਰ ਵੀ ਉਲਝਣਭਰੀ ਹੋ ਜਾਂਦੀ ਹੈ। ਇਹ foo.bar ਨੂੰ ਸਵੀਕਾਰ ਕਰਦੀ ਹੈ ਅਤੇ autoexec.bat ਨੂੰ ਰੱਦ ਕਰਦੀ ਹੈ, ਪਰ ਇਹ ਤਿੰਨ-ਅੱਖਰੀ extension ਦੀ ਮੰਗ ਕਰਦੀ ਹੈ ਅਤੇ sendmail.cf ਵਰਗੀ ਦੋ-ਅੱਖਰੀ extension ਵਾਲੀ filename ਨੂੰ ਸਵੀਕਾਰ ਨਹੀਂ ਕਰਦੀ। ਇਸਨੂੰ ਠੀਕ ਕਰਨ ਲਈ ਅਸੀਂ pattern ਨੂੰ ਹੋਰ ਵੀ ਜਟਿਲ ਬਣਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਾਂਗੇ।
.*[.]([^b].?.?|.[^a]?.?|..?[^t]?)$
ਤੀਜੇ ਯਤਨ ਵਿੱਚ, ਦੂਜੇ ਅਤੇ ਤੀਜੇ ਅੱਖਰਾਂ ਨੂੰ ਵਿਕਲਪਿਕ ਬਣਾ ਦਿੱਤਾ ਗਿਆ ਹੈ ਤਾਂ ਜੋ ਤਿੰਨ ਅੱਖਰਾਂ ਤੋਂ ਛੋਟੀਆਂ ਐਕਸਟੈਂਸ਼ਨਾਂ ਨਾਲ ਵੀ ਮੇਲ ਕੀਤਾ ਜਾ ਸਕੇ, ਜਿਵੇਂ ਕਿ sendmail.cf।
ਹੁਣ ਪੈਟਰਨ ਕਾਫ਼ੀ ਜਟਿਲ ਹੋ ਗਿਆ ਹੈ, ਜਿਸ ਕਾਰਨ ਇਸਨੂੰ ਪੜ੍ਹਨਾ ਅਤੇ ਸਮਝਣਾ ਮੁਸ਼ਕਲ ਹੋ ਜਾਂਦਾ ਹੈ। ਇਸ ਤੋਂ ਵੀ ਬੁਰਾ ਇਹ ਹੈ ਕਿ ਜੇ ਸਮੱਸਿਆ ਬਦਲ ਜਾਵੇ ਅਤੇ ਤੁਸੀਂ bat ਅਤੇ exe ਦੋਵੇਂ ਐਕਸਟੈਂਸ਼ਨਾਂ ਨੂੰ ਬਾਹਰ ਰੱਖਣਾ ਚਾਹੋ, ਤਾਂ ਪੈਟਰਨ ਹੋਰ ਵੀ ਜਟਿਲ ਅਤੇ ਉਲਝਣ ਭਰਿਆ ਹੋ ਜਾਵੇਗਾ।
ਨਕਾਰਾਤਮਕ ਲੁੱਕਅਹੈੱਡ ਇਸ ਸਾਰੀ ਉਲਝਣ ਨੂੰ ਦੂਰ ਕਰ ਦਿੰਦਾ ਹੈ:
.*[.](?!bat$)[^.]*$
ਨਕਾਰਾਤਮਕ ਲੁੱਕਅਹੈੱਡ ਦਾ ਅਰਥ ਹੈ: ਜੇ ਇਸ ਸਥਾਨ 'ਤੇ bat ਐਕਸਪ੍ਰੈਸ਼ਨ ਨਾਲ ਮੇਲ ਨਹੀਂ ਖਾਂਦਾ, ਤਾਂ ਪੈਟਰਨ ਦੇ ਬਾਕੀ ਹਿੱਸੇ ਦੀ ਜਾਂਚ ਕਰੋ; ਜੇ bat$ ਨਾਲ ਮੇਲ ਖਾ ਜਾਂਦਾ ਹੈ, ਤਾਂ ਪੂਰਾ ਪੈਟਰਨ ਅਸਫਲ ਹੋ ਜਾਵੇਗਾ। ਅੰਤ ਵਿੱਚ ਦਿੱਤਾ $ ਇਹ ਯਕੀਨੀ ਬਣਾਉਣ ਲਈ ਲਾਜ਼ਮੀ ਹੈ ਕਿ sample.batch ਵਰਗਾ ਨਾਮ, ਜਿਸਦੀ ਐਕਸਟੈਂਸ਼ਨ ਸਿਰਫ਼ bat ਨਾਲ ਸ਼ੁਰੂ ਹੁੰਦੀ ਹੈ, ਮਨਜ਼ੂਰ ਕੀਤਾ ਜਾਵੇ। [^.]* ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਫਾਇਲ-ਨਾਂ ਵਿੱਚ ਕਈ ਡਾਟ ਹੋਣ 'ਤੇ ਵੀ ਪੈਟਰਨ ਠੀਕ ਤਰ੍ਹਾਂ ਕੰਮ ਕਰੇ।
ਕਿਸੇ ਹੋਰ ਫਾਇਲ ਐਕਸਟੈਂਸ਼ਨ ਨੂੰ ਬਾਹਰ ਰੱਖਣਾ ਹੁਣ ਆਸਾਨ ਹੈ; ਉਸਨੂੰ assertion ਦੇ ਅੰਦਰ ਇੱਕ ਵਿਕਲਪ ਵਜੋਂ ਸ਼ਾਮਲ ਕਰ ਦਿਓ। ਹੇਠਾਂ ਦਿੱਤਾ ਪੈਟਰਨ ਉਹਨਾਂ ਫਾਇਲ-ਨਾਂਵਾਂ ਨੂੰ ਬਾਹਰ ਰੱਖਦਾ ਹੈ ਜੋ bat ਜਾਂ exe ਵਿੱਚ ਖਤਮ ਹੁੰਦੇ ਹਨ:
.*[.](?!bat$|exe$)[^.]*$
ਸਟ੍ਰਿੰਗਾਂ ਵਿੱਚ ਸੋਧ ਕਰਨਾ¶
ਹੁਣ ਤੱਕ ਅਸੀਂ ਸਿਰਫ਼ ਇੱਕ ਸਥਿਰ ਸਟਰਿੰਗ 'ਤੇ ਖੋਜ ਕੀਤੀ ਹੈ। ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਆਮ ਤੌਰ 'ਤੇ ਸਟਰਿੰਗਾਂ ਨੂੰ ਵੱਖ-ਵੱਖ ਢੰਗਾਂ ਨਾਲ ਸੋਧਣ ਲਈ ਵੀ ਵਰਤੇ ਜਾਂਦੇ ਹਨ, ਹੇਠਾਂ ਦਿੱਤੀਆਂ ਪੈਟਰਨ ਵਿਧੀਆਂ ਦੀ ਵਰਤੋਂ ਕਰਕੇ:
Method/Attribute |
ਉਦੇਸ਼ |
|---|---|
|
ਸਟ੍ਰਿੰਗ ਨੂੰ ਸੂਚੀ ਵਿੱਚ ਵੰਡਦਾ ਹੈ, ਜਿੱਥੇ-ਜਿੱਥੇ RE ਨਾਲ ਮੇਲ ਹੁੰਦਾ ਹੈ ਉੱਥੇ ਵੰਡ ਕਰਦਾ ਹੈ। |
|
ਉਹ ਸਾਰੀਆਂ ਉਪ-ਸਟ੍ਰਿੰਗਾਂ ਲੱਭਦਾ ਹੈ ਜਿੱਥੇ RE ਨਾਲ ਮੇਲ ਹੁੰਦਾ ਹੈ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਕਿਸੇ ਹੋਰ ਸਟਰਿੰਗ ਨਾਲ ਬਦਲ ਦਿੰਦਾ ਹੈ। |
|
ਇਹ |
ਸਟ੍ਰਿੰਗਾਂ ਨੂੰ ਵੰਡਣਾ¶
ਕਿਸੇ ਪੈਟਰਨ ਦੀ split() ਵਿਧੀ ਸਟਰਿੰਗ ਨੂੰ ਉੱਥੇ-ਉੱਥੇ ਵੰਡ ਦਿੰਦੀ ਹੈ ਜਿੱਥੇ RE ਨਾਲ ਮੇਲ ਹੁੰਦਾ ਹੈ, ਅਤੇ ਟੁਕੜਿਆਂ ਦੀ ਇੱਕ ਸੂਚੀ ਵਾਪਸ ਕਰਦੀ ਹੈ। ਇਹ ਸਟਰਿੰਗਾਂ ਦੀ split() ਵਿਧੀ ਵਰਗੀ ਹੈ, ਪਰ ਜਿਨ੍ਹਾਂ delimiter ਦੇ ਆਧਾਰ 'ਤੇ ਤੁਸੀਂ ਵੰਡ ਸਕਦੇ ਹੋ ਉਹਨਾਂ ਵਿੱਚ ਕਾਫ਼ੀ ਵੱਧ ਲਚਕੀਲਾਪਣ ਦਿੰਦੀ ਹੈ; ਸਟਰਿੰਗ ਦੀ split() ਸਿਰਫ਼ whitespace ਜਾਂ ਕਿਸੇ ਨਿਰਧਾਰਤ ਸਟਰਿੰਗ ਦੁਆਰਾ ਵੰਡ ਦਾ ਸਮਰਥਨ ਕਰਦੀ ਹੈ। ਜਿਵੇਂ ਤੁਸੀਂ ਉਮੀਦ ਕਰੋਗੇ, ਇਸ ਲਈ ਮੋਡੀਊਲ-ਪੱਧਰੀ re.split() ਫੰਕਸ਼ਨ ਵੀ ਉਪਲਬਧ ਹੈ।
- .split(string[, maxsplit=0])
ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਦੇ ਮੇਲਾਂ ਦੇ ਆਧਾਰ 'ਤੇ string ਨੂੰ ਵੰਡੋ। ਜੇ RE ਵਿੱਚ capturing parentheses ਵਰਤੇ ਗਏ ਹਨ, ਤਾਂ ਉਹਨਾਂ ਦੀ ਸਮੱਗਰੀ ਵੀ ਨਤੀਜੇ ਵਜੋਂ ਮਿਲਣ ਵਾਲੀ ਸੂਚੀ ਦਾ ਹਿੱਸਾ ਬਣ ਕੇ ਵਾਪਸ ਕੀਤੀ ਜਾਵੇਗੀ। ਜੇ maxsplit ਗੈਰ-ਸ਼ੂਨ੍ਯ ਹੈ, ਤਾਂ ਵੱਧ ਤੋਂ ਵੱਧ maxsplit ਵੰਡਾਂ ਹੀ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ।
ਤੁਸੀਂ maxsplit ਲਈ ਇੱਕ ਮੁੱਲ ਦੇ ਕੇ ਕੀਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ ਵੰਡਾਂ ਦੀ ਗਿਣਤੀ ਸੀਮਿਤ ਕਰ ਸਕਦੇ ਹੋ। ਜਦੋਂ maxsplit ਗੈਰ-ਸ਼ੂਨਯ ਹੋਵੇ, ਤਾਂ ਵੱਧ ਤੋਂ ਵੱਧ maxsplit ਵੰਡਾਂ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ ਅਤੇ ਸਟਰਿੰਗ ਦਾ ਬਾਕੀ ਹਿੱਸਾ ਸੂਚੀ ਦੇ ਆਖਰੀ ਤੱਤ ਵਜੋਂ ਵਾਪਸ ਕੀਤਾ ਜਾਵੇਗਾ। ਹੇਠਾਂ ਦਿੱਤੇ ਉਦਾਹਰਨ ਵਿੱਚ, ਡਿਲੀਮੀਟਰ ਕੋਈ ਵੀ ਗੈਰ-ਅੱਖਰ-ਅੰਕੀ ਅੱਖਰਾਂ ਦੀ ਲੜੀ ਹੈ।
>>> p = re.compile(r'\W+')
>>> p.split('This is a test, short and sweet, of split().')
['This', 'is', 'a', 'test', 'short', 'and', 'sweet', 'of', 'split', '']
>>> p.split('This is a test, short and sweet, of split().', 3)
['This', 'is', 'a', 'test, short and sweet, of split().']
ਕਈ ਵਾਰ ਤੁਹਾਡੀ ਦਿਲਚਸਪੀ ਸਿਰਫ਼ ਡਿਲੀਮੀਟਰਾਂ ਦੇ ਵਿਚਕਾਰਲੇ ਪਾਠ ਵਿੱਚ ਨਹੀਂ ਹੁੰਦੀ, ਸਗੋਂ ਇਹ ਜਾਣਨ ਵਿੱਚ ਵੀ ਹੁੰਦੀ ਹੈ ਕਿ ਡਿਲੀਮੀਟਰ ਕੀ ਸੀ। ਜੇ RE ਵਿੱਚ ਕੈਪਚਰਿੰਗ ਕੋਠੀਆਂ ਵਰਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ, ਤਾਂ ਉਹਨਾਂ ਦੇ ਮੁੱਲ ਵੀ ਸੂਚੀ ਦੇ ਹਿੱਸੇ ਵਜੋਂ ਵਾਪਸ ਕੀਤੇ ਜਾਂਦੇ ਹਨ। ਹੇਠਾਂ ਦਿੱਤੀਆਂ ਕਾਲਾਂ ਦੀ ਤੁਲਨਾ ਕਰੋ:
>>> p = re.compile(r'\W+')
>>> p2 = re.compile(r'(\W+)')
>>> p.split('This... is a test.')
['This', 'is', 'a', 'test', '']
>>> p2.split('This... is a test.')
['This', '... ', 'is', ' ', 'a', ' ', 'test', '.', '']
ਮੋਡੀਊਲ-ਪੱਧਰੀ ਫੰਕਸ਼ਨ re.split() ਪਹਿਲੇ ਆਰਗਿਊਮੈਂਟ ਵਜੋਂ ਵਰਤੇ ਜਾਣ ਵਾਲੇ RE ਨੂੰ ਜੋੜਦਾ ਹੈ, ਪਰ ਇਸ ਤੋਂ ਇਲਾਵਾ ਇਹ ਬਿਲਕੁਲ ਉਹੀ ਕੰਮ ਕਰਦਾ ਹੈ।
>>> re.split(r'[\W]+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split(r'([\W]+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split(r'[\W]+', 'Words, words, words.', 1)
['Words', 'words, words.']
ਖੋਜ ਅਤੇ ਬਦਲੀ¶
ਇੱਕ ਹੋਰ ਆਮ ਕੰਮ ਹੈ ਕਿਸੇ ਪੈਟਰਨ ਨਾਲ ਹੋਏ ਸਾਰੇ ਮੇਲ ਲੱਭਣਾ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਕਿਸੇ ਹੋਰ ਸਟ੍ਰਿੰਗ ਨਾਲ ਬਦਲਣਾ। sub() ਵਿਧੀ ਇੱਕ ਬਦਲੀ ਮੁੱਲ ਲੈਂਦੀ ਹੈ, ਜੋ ਜਾਂ ਤਾਂ ਇੱਕ ਸਟਰਿੰਗ ਹੋ ਸਕਦੀ ਹੈ ਜਾਂ ਇੱਕ ਫੰਕਸ਼ਨ, ਅਤੇ ਨਾਲ ਹੀ ਉਹ ਸਟਰਿੰਗ ਜਿਸ 'ਤੇ ਕਾਰਵਾਈ ਕੀਤੀ ਜਾਣੀ ਹੈ।
- .sub(replacement, string[, count=0])
string ਵਿੱਚ RE ਦੇ ਸਭ ਤੋਂ ਖੱਬੇ ਗੈਰ-ਓਵਰਲੈਪਿੰਗ ਮੇਲਾਂ ਨੂੰ replacement ਨਾਲ ਬਦਲ ਕੇ ਪ੍ਰਾਪਤ ਹੋਈ ਸਟਰਿੰਗ ਵਾਪਸ ਕਰਦਾ ਹੈ। ਜੇ ਪੈਟਰਨ ਨਹੀਂ ਮਿਲਦਾ, ਤਾਂ string ਨੂੰ ਬਿਨਾਂ ਕਿਸੇ ਤਬਦੀਲੀ ਦੇ ਵਾਪਸ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।
ਵਿਕਲਪਿਕ ਆਰਗਿਊਮੈਂਟ count ਪੈਟਰਨ ਦੀਆਂ ਉਹਨਾਂ ਘਟਨਾਵਾਂ ਦੀ ਵੱਧ ਤੋਂ ਵੱਧ ਗਿਣਤੀ ਹੈ ਜਿਨ੍ਹਾਂ ਨੂੰ ਬਦਲਿਆ ਜਾਣਾ ਹੈ; count ਇੱਕ ਗੈਰ-ਰਣਾਤਮਕ ਪੂਰਨ ਅੰਕ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ। 0 ਦਾ ਮੂਲ ਮੁੱਲ ਸਾਰੀਆਂ ਘਟਨਾਵਾਂ ਨੂੰ ਬਦਲਣ ਦਾ ਅਰਥ ਰੱਖਦਾ ਹੈ।
ਇੱਥੇ sub() ਵਿਧੀ ਦੀ ਵਰਤੋਂ ਦਾ ਇੱਕ ਸਧਾਰਣ ਉਦਾਹਰਨ ਹੈ। ਇਹ ਰੰਗਾਂ ਦੇ ਨਾਮਾਂ ਨੂੰ colour ਸ਼ਬਦ ਨਾਲ ਬਦਲ ਦਿੰਦੀ ਹੈ:
">>> p = re.compile('(blue|white|red)')\n"
">>> p.sub('colour', 'blue socks and red shoes')\n"
"'colour socks and colour shoes'\n"
">>> p.sub('colour', 'blue socks and red shoes', count=1)\n"
"'colour socks and red shoes'"
subn() ਵਿਧੀ ਵੀ ਇਹੀ ਕੰਮ ਕਰਦੀ ਹੈ, ਪਰ ਇਹ ਇੱਕ 2-ਟਿਊਪਲ ਵਾਪਸ ਕਰਦੀ ਹੈ ਜਿਸ ਵਿੱਚ ਨਵੀਂ ਸਟਰਿੰਗ ਦਾ ਮੁੱਲ ਅਤੇ ਕੀਤੀਆਂ ਗਈਆਂ ਤਬਦੀਲੀਆਂ ਦੀ ਗਿਣਤੀ ਸ਼ਾਮਲ ਹੁੰਦੀ ਹੈ:
">>> p = re.compile('(blue|white|red)')\n"
">>> p.subn('colour', 'blue socks and red shoes')\n"
"('colour socks and colour shoes', 2)\n"
">>> p.subn('colour', 'no colours at all')\n"
"('no colours at all', 0)"
ਖਾਲੀ ਮੇਲਾਂ ਨੂੰ ਕੇਵਲ ਉਸ ਵੇਲੇ ਬਦਲਿਆ ਜਾਂਦਾ ਹੈ ਜਦੋਂ ਉਹ ਪਿਛਲੇ ਖਾਲੀ ਮੇਲ ਦੇ ਨਾਲ ਲੱਗਦੇ ਨਾ ਹੋਣ।
>>> p = re.compile('x*')
>>> p.sub('-', 'abxd')
'-a-b--d-'
ਜੇ replacement ਇੱਕ ਸਟਰਿੰਗ ਹੈ, ਤਾਂ ਇਸ ਵਿੱਚ ਮੌਜੂਦ ਬੈਕਸਲੈਸ਼ ਐਸਕੇਪਾਂ ਦੀ ਪ੍ਰਕਿਰਿਆ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਉਦਾਹਰਨ ਵਜੋਂ, \n ਨੂੰ ਇੱਕ ਨਵੀਂ ਲਾਈਨ ਅੱਖਰ ਵਿੱਚ ਬਦਲਿਆ ਜਾਂਦਾ ਹੈ, \r ਨੂੰ ਕੈਰਿਜ ਰਿਟਰਨ ਵਿੱਚ ਬਦਲਿਆ ਜਾਂਦਾ ਹੈ, ਆਦਿ। ਅਣਪਛਾਤੀਆਂ ਐਸਕੇਪਾਂ ਜਿਵੇਂ \& ਨੂੰ ਜਿਵੇਂ ਦਾ ਤਿਵੇਂ ਛੱਡ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ। ਬੈਕਰੈਫਰੈਂਸਾਂ, ਜਿਵੇਂ \6, ਨੂੰ RE ਵਿੱਚ ਸੰਬੰਧਿਤ ਗਰੁੱਪ ਨਾਲ ਮੇਲ ਖਾਂਦੀ ਉਪ-ਸਟਰਿੰਗ ਨਾਲ ਬਦਲਿਆ ਜਾਂਦਾ ਹੈ। ਇਸ ਨਾਲ ਤੁਸੀਂ ਨਤੀਜੇ ਵਾਲੀ ਬਦਲੀ ਸਟਰਿੰਗ ਵਿੱਚ ਮੂਲ ਪਾਠ ਦੇ ਹਿੱਸੇ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ।
ਇਹ ਉਦਾਹਰਨ section ਸ਼ਬਦ ਨਾਲ ਮੇਲ ਖਾਂਦੀ ਹੈ ਜਿਸ ਤੋਂ ਬਾਅਦ { ਅਤੇ } ਵਿੱਚ ਘਿਰੀ ਇੱਕ ਸਟਰਿੰਗ ਹੁੰਦੀ ਹੈ, ਅਤੇ section ਨੂੰ subsection ਵਿੱਚ ਬਦਲ ਦਿੰਦੀ ਹੈ:
>>> p = re.compile('section{ ( [^}]* ) }', re.VERBOSE)
>>> p.sub(r'subsection{\1}','section{First} section{second}')
'subsection{First} subsection{second}'
(?P<name>...) ਸੰਟੈਕਸ ਦੁਆਰਾ ਪਰਿਭਾਸ਼ਿਤ ਨਾਮਿਤ ਗਰੁੱਪਾਂ ਦਾ ਹਵਾਲਾ ਦੇਣ ਲਈ ਵੀ ਇੱਕ ਸੰਟੈਕਸ ਮੌਜੂਦ ਹੈ। \g<name> ਨਾਮ name ਵਾਲੇ ਗਰੁੱਪ ਨਾਲ ਮੇਲ ਖਾਂਦੀ ਉਪ-ਸਟਰਿੰਗ ਦੀ ਵਰਤੋਂ ਕਰੇਗਾ, ਅਤੇ \g<number> ਸੰਬੰਧਿਤ ਗਰੁੱਪ ਨੰਬਰ ਦੀ ਵਰਤੋਂ ਕਰੇਗਾ। ਇਸ ਲਈ \g<2> , \2 ਦੇ ਬਰਾਬਰ ਹੈ, ਪਰ \g<2>0 ਵਰਗੀ ਬਦਲੀ ਸਟਰਿੰਗ ਵਿੱਚ ਇਹ ਅਸਪਸ਼ਟ ਨਹੀਂ ਹੁੰਦਾ। (\20 ਨੂੰ ਗਰੁੱਪ 20 ਦੇ ਹਵਾਲੇ ਵਜੋਂ ਸਮਝਿਆ ਜਾਵੇਗਾ, ਨਾ ਕਿ ਗਰੁੱਪ 2 ਦੇ ਹਵਾਲੇ ਤੋਂ ਬਾਅਦ ਅੱਖਰ '0' ਵਜੋਂ।) ਹੇਠਾਂ ਦਿੱਤੀਆਂ ਸਾਰੀਆਂ ਬਦਲੀਆਂ ਇੱਕੋ ਜਿਹੀਆਂ ਹਨ, ਪਰ ਬਦਲੀ ਸਟਰਿੰਗ ਦੇ ਤਿੰਨੋਂ ਰੂਪਾਂ ਦੀ ਵਰਤੋਂ ਕਰਦੀਆਂ ਹਨ:
">>> p = re.compile('section{ (?P<name> [^}]* ) }', re.VERBOSE)\n"
">>> p.sub(r'subsection{\\1}','section{First}')\n"
"'subsection{First}'\n"
">>> p.sub(r'subsection{\\g<1>}','section{First}')\n"
"'subsection{First}'\n"
">>> p.sub(r'subsection{\\g<name>}','section{First}')\n"
"'subsection{First}'"
replacement ਇੱਕ ਫੰਕਸ਼ਨ ਵੀ ਹੋ ਸਕਦਾ ਹੈ, ਜੋ ਤੁਹਾਨੂੰ ਹੋਰ ਵੱਧ ਨਿਯੰਤਰਣ ਦਿੰਦਾ ਹੈ। ਜੇ replacement ਇੱਕ ਫੰਕਸ਼ਨ ਹੈ, ਤਾਂ pattern ਦੇ ਹਰ ਗੈਰ-ਓਵਰਲੈਪਿੰਗ ਮੇਲ ਲਈ ਉਹ ਫੰਕਸ਼ਨ ਕਾਲ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਹਰ ਕਾਲ 'ਤੇ, ਫੰਕਸ਼ਨ ਨੂੰ ਮੇਲ ਲਈ ਇੱਕ match object ਆਰਗਿਊਮੈਂਟ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ ਅਤੇ ਇਹ ਇਸ ਜਾਣਕਾਰੀ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਲੋੜੀਂਦੀ ਬਦਲੀ ਸਟਰਿੰਗ ਤਿਆਰ ਕਰਕੇ ਵਾਪਸ ਕਰ ਸਕਦਾ ਹੈ।
ਹੇਠਾਂ ਦਿੱਤੇ ਉਦਾਹਰਨ ਵਿੱਚ, ਬਦਲੀ ਫੰਕਸ਼ਨ ਦਸ਼ਮਲਵ ਸੰਖਿਆਵਾਂ ਨੂੰ ਹੈਕਸਾਡੈਸੀਮਲ ਵਿੱਚ ਤਬਦੀਲ ਕਰਦਾ ਹੈ:
>>> def hexrepl(match):
... "Return the hex string for a decimal number"
... value = int(match.group())
... return hex(value)
...
>>> p = re.compile(r'\d+')
>>> p.sub(hexrepl, 'Call 65490 for printing, 49152 for user code.')
'Call 0xffd2 for printing, 0xc000 for user code.'
ਮੋਡੀਊਲ-ਪੱਧਰੀ re.sub() ਫੰਕਸ਼ਨ ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ, ਪੈਟਰਨ ਪਹਿਲੇ ਆਰਗਿਊਮੈਂਟ ਵਜੋਂ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ। ਪੈਟਰਨ ਨੂੰ ਇੱਕ ਆਬਜੈਕਟ ਜਾਂ ਸਟਰਿੰਗ ਵਜੋਂ ਦਿੱਤਾ ਜਾ ਸਕਦਾ ਹੈ; ਜੇ ਤੁਹਾਨੂੰ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਫਲੈਗ ਨਿਰਧਾਰਤ ਕਰਨ ਦੀ ਲੋੜ ਹੈ, ਤਾਂ ਤੁਹਾਨੂੰ ਜਾਂ ਤਾਂ ਪਹਿਲੇ ਪੈਰਾਮੀਟਰ ਵਜੋਂ ਇੱਕ ਪੈਟਰਨ ਆਬਜੈਕਟ ਵਰਤਣਾ ਹੋਵੇਗਾ ਜਾਂ ਪੈਟਰਨ ਸਟਰਿੰਗ ਵਿੱਚ ਐਂਬੈਡਡ ਮੋਡੀਫਾਇਰ ਵਰਤਣੇ ਹੋਣਗੇ। ਉਦਾਹਰਨ ਲਈ, sub("(?i)b+", "x", "bbbb BBBB") ਦਾ ਨਤੀਜਾ 'x x' ਹੁੰਦਾ ਹੈ।
ਆਮ ਸਮੱਸਿਆਵਾਂ¶
ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਕੁਝ ਐਪਲੀਕੇਸ਼ਨਾਂ ਲਈ ਇੱਕ ਸ਼ਕਤੀਸ਼ਾਲੀ ਸਾਧਨ ਹਨ, ਪਰ ਕੁਝ ਮਾਮਲਿਆਂ ਵਿੱਚ ਉਹਨਾਂ ਦਾ ਵਿਹਾਰ ਸਹਿਜ ਨਹੀਂ ਹੁੰਦਾ ਅਤੇ ਕਈ ਵਾਰ ਉਹ ਤੁਹਾਡੀ ਉਮੀਦ ਅਨੁਸਾਰ ਕੰਮ ਨਹੀਂ ਕਰਦੇ। ਇਹ ਭਾਗ ਕੁਝ ਸਭ ਤੋਂ ਆਮ ਗਲਤੀਆਂ ਅਤੇ ਮੁਸ਼ਕਲਾਂ ਵੱਲ ਧਿਆਨ ਦਿਵਾਏਗਾ।
ਸਟਰਿੰਗ ਵਿਧੀਆਂ ਦੀ ਵਰਤੋਂ ਕਰੋ¶
ਕਈ ਵਾਰ re ਮੋਡੀਊਲ ਦੀ ਵਰਤੋਂ ਕਰਨਾ ਗਲਤੀ ਹੋ ਸਕਦੀ ਹੈ। ਜੇ ਤੁਸੀਂ ਕਿਸੇ ਸਥਿਰ ਸਟਰਿੰਗ ਜਾਂ ਇੱਕ ਹੀ ਅੱਖਰ ਵਰਗ ਨਾਲ ਮੇਲ ਕਰ ਰਹੇ ਹੋ ਅਤੇ ਤੁਸੀਂ re ਦੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਜਿਵੇਂ IGNORECASE ਫਲੈਗ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਰਹੇ, ਤਾਂ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਦੀ ਪੂਰੀ ਤਾਕਤ ਦੀ ਲੋੜ ਨਹੀਂ ਹੋ ਸਕਦੀ। ਸਟਰਿੰਗਾਂ ਵਿੱਚ ਸਥਿਰ ਸਟਰਿੰਗਾਂ ਨਾਲ ਕਾਰਵਾਈਆਂ ਕਰਨ ਲਈ ਕਈ ਵਿਧੀਆਂ ਹੁੰਦੀਆਂ ਹਨ ਅਤੇ ਉਹ ਆਮ ਤੌਰ 'ਤੇ ਕਾਫ਼ੀ ਤੇਜ਼ ਹੁੰਦੀਆਂ ਹਨ, ਕਿਉਂਕਿ ਉਹਨਾਂ ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ ਇੱਕ ਛੋਟੇ ਅਤੇ ਉਦੇਸ਼-ਅਨੁਕੂਲਿਤ C ਲੂਪ 'ਤੇ ਆਧਾਰਿਤ ਹੁੰਦੀ ਹੈ, ਨਾ ਕਿ ਵੱਡੇ ਅਤੇ ਆਮ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਇੰਜਣ 'ਤੇ।
ਇੱਕ ਉਦਾਹਰਨ ਕਿਸੇ ਇੱਕ ਸਥਿਰ ਸਟਰਿੰਗ ਨੂੰ ਦੂਜੀ ਨਾਲ ਬਦਲਣ ਦੀ ਹੋ ਸਕਦੀ ਹੈ; ਉਦਾਹਰਨ ਲਈ, ਤੁਸੀਂ word ਨੂੰ deed ਨਾਲ ਬਦਲਣਾ ਚਾਹ ਸਕਦੇ ਹੋ। ਇਸ ਲਈ re.sub() ਠੀਕ ਲੱਗਦਾ ਹੈ, ਪਰ replace() ਵਿਧੀ ਬਾਰੇ ਵੀ ਸੋਚੋ। ਧਿਆਨ ਦਿਓ ਕਿ replace() ਸ਼ਬਦਾਂ ਦੇ ਅੰਦਰ ਮੌਜੂਦ word ਨੂੰ ਵੀ ਬਦਲ ਦੇਵੇਗੀ, ਜਿਸ ਨਾਲ swordfish , sdeedfish ਬਣ ਜਾਵੇਗਾ, ਪਰ ਸਧਾਰਣ RE word ਵੀ ਇਹੀ ਕਰੇਗਾ। (ਸ਼ਬਦਾਂ ਦੇ ਹਿੱਸਿਆਂ 'ਤੇ ਬਦਲੀ ਤੋਂ ਬਚਣ ਲਈ, ਪੈਟਰਨ \bword\b ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਤਾਂ ਜੋ word ਦੇ ਦੋਵਾਂ ਪਾਸਿਆਂ 'ਤੇ ਸ਼ਬਦ ਸੀਮਾ ਹੋਵੇ। ਇਹ ਕੰਮ replace() ਦੀ ਸਮਰੱਥਾ ਤੋਂ ਪਰੇ ਹੈ।)
ਇੱਕ ਹੋਰ ਆਮ ਕੰਮ ਹੈ ਸਟਰਿੰਗ ਵਿੱਚੋਂ ਕਿਸੇ ਇੱਕ ਅੱਖਰ ਦੀ ਹਰ ਘਟਨਾ ਨੂੰ ਹਟਾਉਣਾ ਜਾਂ ਉਸਨੂੰ ਕਿਸੇ ਹੋਰ ਇੱਕ ਅੱਖਰ ਨਾਲ ਬਦਲਣਾ। ਤੁਸੀਂ ਇਹ ਕੰਮ re.sub('\n', ' ', S) ਵਰਗੀ ਕਿਸੇ ਚੀਜ਼ ਨਾਲ ਕਰ ਸਕਦੇ ਹੋ, ਪਰ translate() ਇਹ ਦੋਵੇਂ ਕੰਮ ਕਰ ਸਕਦੀ ਹੈ ਅਤੇ ਕਿਸੇ ਵੀ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਕਾਰਵਾਈ ਨਾਲੋਂ ਤੇਜ਼ ਹੋਵੇਗੀ।
ਸੰਖੇਪ ਵਿੱਚ, re ਮੋਡੀਊਲ ਵੱਲ ਮੁੜਨ ਤੋਂ ਪਹਿਲਾਂ ਇਹ ਵਿਚਾਰ ਕਰੋ ਕਿ ਕੀ ਤੁਹਾਡੀ ਸਮੱਸਿਆ ਨੂੰ ਕਿਸੇ ਤੇਜ਼ ਅਤੇ ਸਧਾਰਣ ਸਟਰਿੰਗ ਵਿਧੀ ਨਾਲ ਹੱਲ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।
prefixmatch() (ਜਿਸਨੂੰ match ਵੀ ਕਿਹਾ ਜਾਂਦਾ ਹੈ) ਬਨਾਮ search()¶
prefixmatch() ਨੂੰ Python 3.15 ਵਿੱਚ match() ਲਈ ਤਰਜੀਹੀ ਨਾਮ ਵਜੋਂ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ ਸੀ। ਇਸ ਤੋਂ ਪਹਿਲਾਂ ਇਹ ਸਿਰਫ਼ match() ਦੇ ਨਾਮ ਨਾਲ ਜਾਣਿਆ ਜਾਂਦਾ ਸੀ ਅਤੇ search() ਨਾਲ ਇਸਦਾ ਅੰਤਰ ਅਕਸਰ ਗਲਤ ਸਮਝਿਆ ਜਾਂਦਾ ਸੀ।
prefixmatch() ਜਾਂ match() ਸਿਰਫ਼ ਇਹ ਜਾਂਚਦਾ ਹੈ ਕਿ RE ਸਟਰਿੰਗ ਦੇ ਸ਼ੁਰੂ ਵਿੱਚ ਮੇਲ ਖਾਂਦਾ ਹੈ ਜਾਂ ਨਹੀਂ, ਜਦਕਿ search() ਮੇਲ ਲੱਭਣ ਲਈ ਸਟਰਿੰਗ ਵਿੱਚ ਅੱਗੇ ਵਧਦਿਆਂ ਖੋਜ ਕਰਦਾ ਹੈ।
>>> print(re.prefixmatch('super', 'superstition').span())
(0, 5)
>>> print(re.prefixmatch('super', 'insuperable'))
None
ਦੂਜੇ ਪਾਸੇ, search() ਸਟਰਿੰਗ ਵਿੱਚ ਅੱਗੇ ਵਧਦਿਆਂ ਖੋਜ ਕਰਦਾ ਹੈ ਅਤੇ ਸਭ ਤੋਂ ਪਹਿਲਾਂ ਮਿਲੇ ਮੇਲ ਦੀ ਰਿਪੋਰਟ ਕਰਦਾ ਹੈ:
>>> print(re.search('super', 'superstition').span())
(0, 5)
>>> print(re.search('super', 'insuperable').span())
(2, 7)
ਪੁਰਾਣੇ Python ਸੰਸਕਰਣਾਂ ਨਾਲ ਅਨੁਕੂਲਤਾ ਦੀ ਲੋੜ ਵਾਲੇ ਕੋਡ ਵਿੱਚ ਪੁਰਾਣੇ match() ਨਾਮ ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ ਇਸ ਅੰਤਰ ਨੂੰ ਯਾਦ ਰੱਖਣਾ ਮਹੱਤਵਪੂਰਨ ਹੈ।
ਲਾਲਚੀ ਬਨਾਮ ਗੈਰ-ਲਾਲਚੀ¶
ਜਦੋਂ ਕਿਸੇ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਨੂੰ ਦੁਹਰਾਇਆ ਜਾਂਦਾ ਹੈ, ਜਿਵੇਂ a* ਵਿੱਚ, ਤਾਂ ਇਸ ਦਾ ਨਤੀਜਾ ਇਹ ਹੁੰਦਾ ਹੈ ਕਿ ਇਹ ਸੰਭਵ ਹੋ ਸਕਣ ਵਾਲੇ ਪੈਟਰਨ ਦੇ ਸਭ ਤੋਂ ਵੱਡੇ ਹਿੱਸੇ ਨੂੰ ਖਪਾ ਲੈਂਦਾ ਹੈ। ਇਹ ਗੱਲ ਅਕਸਰ ਉਸ ਵੇਲੇ ਸਮੱਸਿਆ ਪੈਦਾ ਕਰਦੀ ਹੈ ਜਦੋਂ ਤੁਸੀਂ ਸੰਤੁਲਿਤ ਡਿਲੀਮੀਟਰਾਂ ਦੀ ਜੋੜੀ ਨਾਲ ਮੇਲ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ, ਜਿਵੇਂ HTML ਟੈਗ ਦੇ ਆਲੇ-ਦੁਆਲੇ ਵਾਲੀਆਂ ਐਂਗਲ ਬ੍ਰੈਕਟਾਂ। ਇੱਕ HTML ਟੈਗ ਨਾਲ ਮੇਲ ਕਰਨ ਲਈ ਸਧਾਰਣ ਪੈਟਰਨ .* ਦੀ ਲਾਲਚੀ ਪ੍ਰਕਿਰਤੀ ਕਾਰਨ ਠੀਕ ਕੰਮ ਨਹੀਂ ਕਰਦਾ।
">>> s = '<html><head><title>Title</title>'\n"
">>> len(s)\n"
"32\n"
">>> print(re.prefixmatch('<.*>', s).span())\n"
"(0, 32)\n"
">>> print(re.prefixmatch('<.*>', s).group())\n"
"<html><head><title>Title</title>"
RE, '<html>' ਵਿੱਚ ਮੌਜੂਦ '<' ਨਾਲ ਮੇਲ ਖਾਂਦਾ ਹੈ ਅਤੇ .* ਬਾਕੀ ਸਾਰੀ ਸਟਰਿੰਗ ਨੂੰ ਖਪਾ ਲੈਂਦਾ ਹੈ। ਹਾਲਾਂਕਿ RE ਵਿੱਚ ਹੋਰ ਹਿੱਸਾ ਬਾਕੀ ਰਹਿੰਦਾ ਹੈ ਅਤੇ > ਸਟਰਿੰਗ ਦੇ ਅੰਤ ਨਾਲ ਮੇਲ ਨਹੀਂ ਖਾ ਸਕਦਾ, ਇਸ ਲਈ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਇੰਜਣ ਇੱਕ-ਇੱਕ ਅੱਖਰ ਪਿੱਛੇ ਹਟਦਾ ਹੈ ਜਦ ਤੱਕ ਉਸਨੂੰ > ਲਈ ਮੇਲ ਨਹੀਂ ਮਿਲ ਜਾਂਦਾ। ਅੰਤਿਮ ਮੇਲ '<html>' ਦੇ '<' ਤੋਂ ਲੈ ਕੇ '</title>' ਦੇ '>' ਤੱਕ ਫੈਲਦਾ ਹੈ, ਜੋ ਕਿ ਤੁਸੀਂ ਨਹੀਂ ਚਾਹੁੰਦੇ।
ਇਸ ਮਾਮਲੇ ਵਿੱਚ ਹੱਲ ਹੈ ਗੈਰ-ਲਾਲਚੀ ਮਾਤਰਾਕਾਰਾਂ *?, +?, ?? ਜਾਂ {m,n}? ਦੀ ਵਰਤੋਂ ਕਰਨਾ, ਜੋ ਸੰਭਵ ਹੋ ਸਕਣ ਵਾਲੇ ਸਭ ਤੋਂ ਘੱਟ ਪਾਠ ਨਾਲ ਮੇਲ ਕਰਦੇ ਹਨ। ਉੱਪਰਲੇ ਉਦਾਹਰਨ ਵਿੱਚ, ਪਹਿਲੇ '<' ਨਾਲ ਮੇਲ ਹੋਣ ਤੋਂ ਤੁਰੰਤ ਬਾਅਦ '>' ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਅਤੇ ਜਦੋਂ ਇਹ ਅਸਫਲ ਹੋ ਜਾਂਦੀ ਹੈ, ਤਾਂ ਇੰਜਣ ਇੱਕ-ਇੱਕ ਅੱਖਰ ਅੱਗੇ ਵਧਦਾ ਹੈ ਅਤੇ ਹਰ ਪੜਾਅ 'ਤੇ '>' ਦੀ ਮੁੜ ਜਾਂਚ ਕਰਦਾ ਹੈ। ਇਸ ਨਾਲ ਬਿਲਕੁਲ ਸਹੀ ਨਤੀਜਾ ਮਿਲਦਾ ਹੈ:
">>> print(re.prefixmatch('<.*?>', s).group())\n"
"<html>"
(ਧਿਆਨ ਦਿਓ ਕਿ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਨਾਲ HTML ਜਾਂ XML ਨੂੰ ਪਾਰਸ ਕਰਨਾ ਕਾਫ਼ੀ ਔਖਾ ਹੁੰਦਾ ਹੈ। ਸਧਾਰਣ ਪੈਟਰਨ ਆਮ ਮਾਮਲਿਆਂ ਨੂੰ ਸੰਭਾਲ ਸਕਦੇ ਹਨ, ਪਰ HTML ਅਤੇ XML ਵਿੱਚ ਕਈ ਵਿਸ਼ੇਸ਼ ਮਾਮਲੇ ਹੁੰਦੇ ਹਨ ਜੋ ਆਮ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਨੂੰ ਤੋੜ ਸਕਦੇ ਹਨ। ਜਦ ਤੱਕ ਤੁਸੀਂ ਹਰ ਸੰਭਵ ਮਾਮਲੇ ਨੂੰ ਸੰਭਾਲਣ ਵਾਲਾ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਲਿਖੋਗੇ, ਪੈਟਰਨ ਬਹੁਤ ਜਟਿਲ ਹੋ ਜਾਵੇਗਾ। ਅਜਿਹੇ ਕੰਮਾਂ ਲਈ HTML ਜਾਂ XML ਪਾਰਸਰ ਮੋਡੀਊਲ ਦੀ ਵਰਤੋਂ ਕਰੋ।)
re.VERBOSE ਦੀ ਵਰਤੋਂ¶
ਹੁਣ ਤੱਕ ਤੁਸੀਂ ਸ਼ਾਇਦ ਨੋਟ ਕੀਤਾ ਹੋਵੇਗਾ ਕਿ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਇੱਕ ਬਹੁਤ ਸੰਖੇਪ ਨੋਟੇਸ਼ਨ ਹਨ, ਪਰ ਉਹ ਬਹੁਤ ਪੜ੍ਹਨਯੋਗ ਨਹੀਂ ਹੁੰਦੇ। ਦਰਮਿਆਨੀ ਜਟਿਲਤਾ ਵਾਲੇ RE ਬੈਕਸਲੈਸ਼ਾਂ, ਕੋਠੀਆਂ ਅਤੇ ਮੈਟਾਕੈਰੈਕਟਰਾਂ ਦੇ ਲੰਮੇ ਸਮੂਹ ਬਣ ਸਕਦੇ ਹਨ, ਜਿਸ ਕਾਰਨ ਉਹਨਾਂ ਨੂੰ ਪੜ੍ਹਨਾ ਅਤੇ ਸਮਝਣਾ ਔਖਾ ਹੋ ਜਾਂਦਾ ਹੈ।
ਅਜਿਹੇ RE ਲਈ, ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਨੂੰ ਕੰਪਾਇਲ ਕਰਦੇ ਸਮੇਂ re.VERBOSE ਫਲੈਗ ਨਿਰਧਾਰਤ ਕਰਨਾ ਮਦਦਗਾਰ ਹੋ ਸਕਦਾ ਹੈ, ਕਿਉਂਕਿ ਇਹ ਤੁਹਾਨੂੰ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਨੂੰ ਹੋਰ ਸਪਸ਼ਟ ਢੰਗ ਨਾਲ ਫਾਰਮੈਟ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।
re.VERBOSE ਫਲੈਗ ਦੇ ਕਈ ਪ੍ਰਭਾਵ ਹਨ। ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਵਿੱਚ ਉਹ ਖਾਲੀ ਥਾਂ ਜੋ ਕਿਸੇ ਅੱਖਰ ਵਰਗ ਦੇ ਅੰਦਰ ਨਹੀਂ ਹੈ, ਅਣਡਿੱਠੀ ਕਰ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ। ਇਸਦਾ ਅਰਥ ਹੈ ਕਿ dog | cat ਵਰਗੀ ਐਕਸਪ੍ਰੈਸ਼ਨ ਘੱਟ ਪੜ੍ਹਨਯੋਗ dog|cat ਦੇ ਬਰਾਬਰ ਹੈ, ਪਰ [a b] ਹਾਲੇ ਵੀ 'a', 'b' ਜਾਂ ਇੱਕ ਖਾਲੀ ਥਾਂ ਨਾਲ ਮੇਲ ਖਾਏਗੀ। ਇਸ ਤੋਂ ਇਲਾਵਾ, ਤੁਸੀਂ RE ਦੇ ਅੰਦਰ ਟਿੱਪਣੀਆਂ ਵੀ ਲਿਖ ਸਕਦੇ ਹੋ; ਟਿੱਪਣੀਆਂ # ਅੱਖਰ ਤੋਂ ਅਗਲੀ ਨਵੀਂ ਲਾਈਨ ਤੱਕ ਫੈਲਦੀਆਂ ਹਨ। ਜਦੋਂ ਇਸਦੀ ਵਰਤੋਂ triple-quoted ਸਟਰਿੰਗਾਂ ਨਾਲ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਤਾਂ RE ਨੂੰ ਹੋਰ ਸੁਚੱਜੇ ਢੰਗ ਨਾਲ ਫਾਰਮੈਟ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ:
"pat = re.compile(r\"\"\"\n"
" \\s* # Skip leading whitespace\n"
" (?P<header>[^:]+) # Header name\n"
" \\s* : # Whitespace, and a colon\n"
" (?P<value>.*?) # The header's value -- *? used to\n"
" # lose the following trailing whitespace\n"
" \\s*$ # Trailing whitespace to end-of-line\n"
"\"\"\", re.VERBOSE)"
ਇਹ ਹੇਠਾਂ ਦਿੱਤੀ ਐਕਸਪ੍ਰੈਸ਼ਨ ਨਾਲੋਂ ਕਾਫ਼ੀ ਵੱਧ ਪੜ੍ਹਨਯੋਗ ਹੈ:
"pat = re.compile(r\"\\s*(?P<header>[^:]+)\\s*:(?P<value>.*?)\\s*$\")"
ਫੀਡਬੈਕ¶
ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਇੱਕ ਜਟਿਲ ਵਿਸ਼ਾ ਹਨ। ਕੀ ਇਸ ਦਸਤਾਵੇਜ਼ ਨੇ ਤੁਹਾਨੂੰ ਉਹਨਾਂ ਨੂੰ ਸਮਝਣ ਵਿੱਚ ਮਦਦ ਕੀਤੀ? ਕੀ ਕੋਈ ਭਾਗ ਅਸਪਸ਼ਟ ਸੀ, ਜਾਂ ਕੀ ਤੁਹਾਨੂੰ ਅਜਿਹੀਆਂ ਸਮੱਸਿਆਵਾਂ ਆਈਆਂ ਜਿਨ੍ਹਾਂ ਬਾਰੇ ਇੱਥੇ ਚਰਚਾ ਨਹੀਂ ਕੀਤੀ ਗਈ? ਜੇ ਹਾਂ, ਤਾਂ ਕਿਰਪਾ ਕਰਕੇ ਸੁਧਾਰਾਂ ਲਈ ਆਪਣੇ ਸੁਝਾਅ issue tracker ਨੂੰ ਭੇਜੋ।
ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨਾਂ ਬਾਰੇ ਸਭ ਤੋਂ ਸੰਪੂਰਨ ਕਿਤਾਬ ਲਗਭਗ ਨਿਸ਼ਚਿਤ ਤੌਰ 'ਤੇ Jeffrey Friedl ਦੀ Mastering Regular Expressions ਹੈ, ਜੋ O'Reilly ਵੱਲੋਂ ਪ੍ਰਕਾਸ਼ਿਤ ਕੀਤੀ ਗਈ ਹੈ। ਦੁੱਖ ਦੀ ਗੱਲ ਹੈ ਕਿ ਇਹ ਮੁੱਖ ਤੌਰ 'ਤੇ Perl ਅਤੇ Java ਦੀਆਂ ਰੈਗੂਲਰ ਐਕਸਪ੍ਰੈਸ਼ਨ ਸ਼ੈਲੀਆਂ 'ਤੇ ਕੇਂਦ੍ਰਿਤ ਹੈ ਅਤੇ ਇਸ ਵਿੱਚ Python ਨਾਲ ਸੰਬੰਧਿਤ ਸਮੱਗਰੀ ਨਹੀਂ ਹੈ, ਇਸ ਲਈ Python ਪ੍ਰੋਗਰਾਮਿੰਗ ਲਈ ਇਹ ਇੱਕ ਸੰਦਰਭ ਕਿਤਾਬ ਵਜੋਂ ਬਹੁਤ ਲਾਭਕਾਰੀ ਨਹੀਂ ਹੋਵੇਗੀ। (ਪਹਿਲੇ ਸੰਸਕਰਣ ਵਿੱਚ Python ਦੇ ਹੁਣ ਹਟਾਏ ਜਾ ਚੁੱਕੇ regex ਮੋਡੀਊਲ ਦੀ ਚਰਚਾ ਸੀ, ਜੋ ਤੁਹਾਡੀ ਵੱਡੀ ਮਦਦ ਨਹੀਂ ਕਰੇਗੀ।) ਫਿਰ ਵੀ, ਤੁਸੀਂ ਇਸਨੂੰ ਆਪਣੀ ਲਾਇਬ੍ਰੇਰੀ ਤੋਂ ਵੇਖ ਸਕਦੇ ਹੋ।