بديل للمطابقة = RE.Match ()؛ إذا تطابق: ... `المصطلح؟
سؤال
إذا كنت ترغب في التحقق مما إذا كان هناك شيء يطابق Regex، إذا كان الأمر كذلك، فقم بطباعة المجموعة الأولى، أنت تفعل ..
import re
match = re.match("(\d+)g", "123g")
if match is not None:
print match.group(1)
هذا محور تماما، ولكن الوسيط match
المتغير مزعج بعض الشيء ..
لغات مثل perl القيام بذلك عن طريق إنشاء جديد $1
..$9
المتغيرات لمجموعات المباريات، مثل ..
if($blah ~= /(\d+)g/){
print $1
}
with re_context.match('^blah', s) as match:
if match:
...
else:
...
لقد اعتقدت أن فكرة مثيرة للاهتمام، لذلك كتبت تطبيقا بسيطا له:
#!/usr/bin/env python2.6
import re
class SRE_Match_Wrapper:
def __init__(self, match):
self.match = match
def __exit__(self, type, value, tb):
pass
def __enter__(self):
return self.match
def __getattr__(self, name):
if name == "__exit__":
return self.__exit__
elif name == "__enter__":
return self.__name__
else:
return getattr(self.match, name)
def rematch(pattern, inp):
matcher = re.compile(pattern)
x = SRE_Match_Wrapper(matcher.match(inp))
return x
return match
if __name__ == '__main__':
# Example:
with rematch("(\d+)g", "123g") as m:
if m:
print(m.group(1))
with rematch("(\d+)g", "123") as m:
if m:
print(m.group(1))
(هذه الوظيفة يمكن تصحيحها نظريا في _sre.SRE_Match
هدف)
سيكون من الرائع أن تخطي تنفيذ with
كتلة شفرة البيان، إذا لم تكن هناك مباراة، والتي من شأنها تبسيط ذلك ..
with rematch("(\d+)g", "123") as m:
print(m.group(1)) # only executed if the match occurred
.. لكن هذا يبدو مستحيلا بناء على ما يمكنني استنتاج من بيب 343.
أيه أفكار؟ كما قلت، هذا إزعاج تافهة حقا، تقريبا إلى حد كون الجولف ..
المحلول
بدءا Python 3.8
, ، وإدخال تعبيرات التعيين (PEP 572) (:=
المشغل)، يمكننا الآن التقاط قيمة الشرط re.match(r'(\d+)g', '123g')
في متغير match
من أجل كل من الشيك إذا لم يكن كذلك None
ثم أعد استخدامها داخل جسم الحالة:
>>> if match := re.match(r'(\d+)g', '123g'):
... print(match.group(1))
...
123
>>> if match := re.match(r'(\d+)g', 'dddf'):
... print(match.group(1))
...
>>>
نصائح أخرى
لا أعتقد أنها تافهة. لا أريد أن أضع مع رش مشروط زائدة عن الزيادة حول التعليمات البرمجية إذا أكتب رمز مثل هذا في كثير من الأحيان.
هذا غريب بعض الشيء، ولكن يمكنك القيام بذلك مع جهاز كمتكر
import re
def rematch(pattern, inp):
matcher = re.compile(pattern)
matches = matcher.match(inp)
if matches:
yield matches
if __name__ == '__main__':
for m in rematch("(\d+)g", "123g"):
print(m.group(1))
الشيء الغريب هو أنه يستخدم جهاز كمتقل لشيء لا يتنكر - إنه أقرب إلى مشروط، واللقاء الأول قد يبدو أنه سيؤدي إلى تحقيق نتائج متعددة لكل مباراة.
يبدو من الغريب أن مدير السياق لا يستطيع تخطي وظيفته المدارة بالكامل؛ في حين أن هذا ليس أحد صريحا من حالات استخدام "مع"، إلا أنه يبدو وكأنه تمديد طبيعي.
بناء جملة لطيف آخر سيكون مثل هذا:
header = re.compile('(.*?) = (.*?)$')
footer = re.compile('(.*?): (.*?)$')
if header.match(line) as m:
key, value = m.group(1,2)
elif footer.match(line) as m
key, value = m.group(1,2)
else:
key, value = None, None
لدي طريقة أخرى للقيام بذلك، بناء على محلول Glen Maynard:
for match in [m for m in [re.match(pattern,key)] if m]:
print "It matched: %s" % match
على غرار حل Glen، فإن هذا إما 0 (إذا لم يكن هناك تطابق) أو 1 (إذا كانت المباراة) مرات.
لا تحتاج دون الحاجة، ولكن أقل مرتبة نتيجة لذلك.
إذا كنت تفعل الكثير من هذه في مكان واحد، فإليك إجابة بديلة:
import re
class Matcher(object):
def __init__(self):
self.matches = None
def set(self, matches):
self.matches = matches
def __getattr__(self, name):
return getattr(self.matches, name)
class re2(object):
def __init__(self, expr):
self.re = re.compile(expr)
def match(self, matcher, s):
matches = self.re.match(s)
matcher.set(matches)
return matches
pattern = re2("(\d+)g")
m = Matcher()
if pattern.match(m, "123g"):
print(m.group(1))
if not pattern.match(m, "x123g"):
print "no match"
يمكنك ترجمة Regex مرة واحدة مع نفس سلامة الخيط مثل إعادة، وإنشاء كائن Matcher واحد قابل لإعادة الاستخدام لهذه الوظيفة بأكملها، ثم يمكنك استخدامه بإيجاز للغاية. تتمتع ذلك أيضا بالفائدة التي يمكنك عكسها بطريقة واضحة - للقيام بذلك مع جهاز كمتكر فيه، كنت بحاجة إلى اجتياز العلم لتخبره عن عكس النتيجة.
لا يساعد الكثير إذا كنت تقوم بمباراة واحدة فقط لكل وظيفة، على الرغم من ذلك؛ أنت لا ترغب في الحفاظ على كائنات Matcher في سياق أوسع من ذلك؛ لأنه سيؤدي إلى نفس المشكلات مثل حل Blott.
لا أعتقد ذلك with
هو الحل في هذه الحالة. يجب عليك رفع استثناء في BLOCK
جزء (الذي يحدده المستخدم) ولديك __exit__
طريقة العودة True
إلى "ابتلاع" الاستثناء. لذلك لن تبدو جيدة.
أقترح الذهاب إلى بناء جملة مماثل لبوليات بيرل. اصنع امتدت re
الوحدة النمطية (سأتصل به rex
) ولديها تحدد المتغيرات في مساحة الاسم الوحدة النمطية:
if rex.match('(\d+)g', '123g'):
print rex._1
كما ترون في التعليقات أدناه، هذه الطريقة ليست نطاقا أو آمنا للخيط. ستستخدم هذا فقط إذا كنت متأكدا تماما من أن تطبيقك لن يصبح متعدد الخيوط في المستقبل وأن أي وظائف تسمى من النطاق الذي تستخدمه في الإرادة أيضا استخدم نفس الطريقة.
هذا ليس رائعا حقا، ولكن يمكنك الاستفادة من getattr(object, name[, default])
وظيفة مدمجة باستخدامه مثل هذا:
>>> getattr(re.match("(\d+)g", "123g"), 'group', lambda n:'')(1)
'123'
>>> getattr(re.match("(\d+)g", "X23g"), 'group', lambda n:'')(1)
''
لتقليد إذا تطابق مجموعة الطباعة التدفق، يمكنك (AB) استخدام for
بيان بهذه الطريقة:
>>> for group in filter(None, [getattr(re.match("(\d+)g", "123g"), 'group', None)]):
print(group(1))
123
>>> for group in filter(None, [getattr(re.match("(\d+)g", "X23g"), 'group', None)]):
print(group(1))
>>>
بالطبع يمكنك تحديد وظيفة صغيرة للقيام بالعمل القذر:
>>> matchgroup = lambda p,s: filter(None, [getattr(re.match(p, s), 'group', None)])
>>> for group in matchgroup("(\d+)g", "123g"):
print(group(1))
123
>>> for group in matchgroup("(\d+)g", "X23g"):
print(group(1))
>>>
ليس الحل المثالي، ولكنه يسمح لك بسلسلة خيارات مباراة متعددة لنفس STR:
class MatchWrapper(object):
def __init__(self):
self._matcher = None
def wrap(self, matcher):
self._matcher = matcher
def __getattr__(self, attr):
return getattr(self._matcher, attr)
def match(pattern, s, matcher):
m = re.match(pattern, s)
if m:
matcher.wrap(m)
return True
else:
return False
matcher = MatchWrapper()
s = "123g";
if _match("(\d+)g", line, matcher):
print matcher.group(1)
elif _match("(\w+)g", line, matcher):
print matcher.group(1)
else:
print "no match"
إليك حلاي:
import re
s = 'hello world'
match = []
if match.append(re.match('w\w+', s)) or any(match):
print('W:', match.pop().group(0))
elif match.append(re.match('h\w+', s)) or any(match):
print('H:', match.pop().group(0))
else:
print('No match found')
يمكنك استخدام أكبر عدد ممكن أليف البنود حسب الحاجة.
حتى أفضل:
import re
s = 'hello world'
if vars().update(match=re.match('w\w+', s)) or match:
print('W:', match.group(0))
elif vars().update(match=re.match('h\w+', s)) or match:
print('H:', match.group(0))
else:
print('No match found')
كلاهما ألحق و تحديث إرجاع لا أحد. وبعد لذلك عليك أن تحقق فعلا نتيجة تعبيرك باستخدام أو جزء في كل حالة.
لسوء الحظ، هذا يعمل فقط طالما أن الرمز يقيم المستوى الأعلى، أي ليس في وظيفة.
هذا ما افعله:
def re_match_cond (match_ref, regex, text):
match = regex.match (text)
del match_ref[:]
match_ref.append (match)
return match
if __name__ == '__main__':
match_ref = []
if re_match_cond (match_ref, regex_1, text):
match = match_ref[0]
### ...
elif re_match_cond (match_ref, regex_2, text):
match = match_ref[0]
### ...
elif re_match_cond (match_ref, regex_3, text):
match = match_ref[0]
### ...
else:
### no match
### ...
وهذا هو، وأرمر قائمة إلى الوظيفة لمحاكاة مرجع المرور.