import re
regex = re.compile(r"^(?!##?\s)([^\/\|\@\"!]*?)(##|#[@?$%]{1,3}#|\$@?\$)", flags=re.MULTILINE)
test_str = ("## comment\n"
"# #comment\n\n"
"! Basic rules\n"
"##div\n"
"#@#div\n"
"##.ads\n"
"#@#.ads\n"
"###ads\n"
"#@##ads\n"
"example.com,~example.org##div\n"
"example.com,~example.org#@#div\n"
"example.com,~example.org##.ads\n"
"example.com,~example.org#@#.ads\n"
"example.com,~example.org###ads\n"
"example.com,~example.org#@##ads\n\n"
"! HTML filtering rules\n"
"! https://github.com/gorhill/uBlock/wiki/Static-filter-syntax#html-filters\n"
"example.com##^.badstuff\n"
"example.com##^script:has-text(7c9e3a5d51cdacfc)\n"
"! https://adguard.com/kb/general/ad-filtering/create-own-filters/#html-filtering-rules\n"
"example.org$$script[data-src=\"banner\"]\n"
"example.org$@$script[data-src=\"banner\"]\n\n"
"! CSS rules\n"
"! https://adguard.com/kb/general/ad-filtering/create-own-filters/#cosmetic-css-rules\n"
"example.com#$#div { visibility: hidden; }\n"
"example.com#@$#div { visibility: hidden; }\n"
"example.com#$#.textad { visibility: hidden; }\n"
"example.com#@$#.textad { visibility: hidden; }\n"
"example.com#$##textad { visibility: hidden; }\n"
"example.com#@$##textad { visibility: hidden; }\n\n"
"! Extended CSS selectors\n"
"! https://adguard.com/kb/general/ad-filtering/create-own-filters/#extended-css-selectors\n"
"example.com#?#div:has(> a[target=\"_blank\"][rel=\"nofollow\"])\n"
"example.com#@?#div:has(> a[target=\"_blank\"][rel=\"nofollow\"])\n"
"example.com#?#.banner:matches-css(width: 360px)\n"
"example.com#@?#.banner:matches-css(width: 360px)\n"
"example.com#?##banner:matches-css(width: 360px)\n"
"example.com#@?##banner:matches-css(width: 360px)\n\n"
"example.com#$?#div:has(> span) { display: none !important; }\n"
"example.com#@$?#div:has(> span) { display: none !important; }\n"
"example.com#$?#.banner:has(> span) { display: none !important; }\n"
"example.com#@$?#.banner:has(> span) { display: none !important; }\n"
"example.com#$?##banner:has(> span) { display: none !important; }\n"
"example.com#@$?##banner:has(> span) { display: none !important; }\n\n"
"! JavaScript rules\n"
"! https://adguard.com/kb/general/ad-filtering/create-own-filters/#javascript-rules\n"
"! https://adguard.com/kb/general/ad-filtering/create-own-filters/#scriptlets\n"
"example.com#%#window.__gaq = undefined;\n"
"example.com#@%#window.__gaq = undefined;\n\n"
"! Scriptlet rules\n"
"example.com##+js(aopw, Fingerprint2)\n"
"example.com#@#+js(aopw, Fingerprint2)\n"
"example.org,example.com#%#//scriptlet(\"abort-on-property-read\", \"alert\")\n"
"example.com#@%#//scriptlet(\"abort-on-property-read\")")
matches = regex.finditer(test_str)
for match_num, match in enumerate(matches, start=1):
print(f"Match {match_num} was found at {match.start()}-{match.end()}: {match.group()}")
for group_num, group in enumerate(match.groups(), start=1):
print(f"Group {group_num} found at {match.start(group_num)}-{match.end(group_num)}: {group}")
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for Python, please visit: https://docs.python.org/3/library/re.html