من الممكن استرداد مجموعة تعسفية غير مرتبة من المجموعات المسماة في ضربة واحدة مع وحدة إعادة Python؟

StackOverflow https://stackoverflow.com/questions/2187931

  •  25-09-2019
  •  | 
  •  

سؤال

هذا مفيد للغاية لبعض المشاكل:

>>> re.search('(?P<b>.b.).*(?P<i>.i.)', 'abcdefghijk').groupdict()
{'i': 'hij', 'b': 'abc'}

ولكن ماذا لو لم أكن أعرف ما هو أمر يمكن توقعه في وقت مبكر؟

تحديث

على سبيل المثال ، قل أن لديّ متغير إدخال يحتوي على بعض الترتيب غير المعروف من الشخصيات ويحدث فقط أن "B" يأتي بعد "I". أريد أن أكون قادرًا على الرجوع إلى مجموعات ".B." و انا.' دون الحاجة إلى طلب regex الخاص بي وفقا لترتيبها في إدخال var. لذا ، أتمنى أن أفعل شيئًا كهذا ولكني لا أعرف ما إذا كان ذلك ممكنًا:

>>> re.search('(?P<b>.b.)|(?P<i>.i.)', unknown_order_alphabet_str).groupdict()
{'i': 'hij', 'b': 'abc'}

تحديث النهاية

لقد بحثت حولها ورفعت عقلي حفنة ولكن لا يمكنني توليد أي خيوط جيدة. إن تخمين هذه الوظيفة لن تكون موجودة لأنه ربما الطريقة الوحيدة لإعادة القيام بذلك هي مسح السلسلة بأكملها مرة واحدة لكل مجموعة (والتي بالطبع يمكنني القيام بها في حلقة بدلاً من ذلك) لكنني اعتقدت أنني سأرى ما هو دماغ Stackoverlow كان يجب أن أقول عن ذلك.

شكرا لمساعدتك،
جوش

هل كانت مفيدة؟

المحلول

استخدم شريط عمودي ("أو") في نمط إعادة ، و finditer للحصول على جميع كائنات المطابقة ذات الاهتمام: سيكون لكل منها ملف groupdict مع None كقيمة للمجموعات التي لا تشارك في تلك المباراة ، ويمكنك "دمج" الديكتات كما تفضل.

علي سبيل المثال:

import re

def mergedgroupdict(pattern, thestring):
  there = re.compile(pattern)
  result = {}
  for mo in there.finditer(thestring):
    d = mo.groupdict()
    for k in d:
      if k not in result and d[k] is not None:
        result[k] = d[k]
  return result

يستخدم هذا استراتيجية دمج وهي مجرد اختيار المباراة الفعلية الأولى لكل مجموعة مسماة في النمط. الآن على سبيل المثال

>>> mergedgroupdict('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')
{'i': 'hij', 'b': 'abc'}
>>> mergedgroupdict('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk'[::-1])
{'i': 'jih', 'b': 'cba'}

من المفترض كما تريد ، إذا قمت بتفسير سؤالك بشكل صحيح.

نصائح أخرى

>>> [m.groupdict() for m in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')]
[{'i': None, 'b': 'abc'}, {'i': 'hij', 'b': None}]

يبدو أنه يعمل بشكل جيد ، على الرغم من أنه إذا كان لديك العديد من المجموعات التي تتحقق من أي شخص ليس كذلك None قد تصبح مملة.

هذا يجد كل شيء .b. وكل .i. تطابق في السلسلة. إذا أردت أن تتأكد من أنه وجد أحد كل منها ، فسيتعين عليك التحقق من ذلك يدويًا أيضًا.

الأقرب الذي يمكنني الحصول عليه هو:

>>> [match.groupdict() for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')]
[{'i': None, 'b': 'abc'}, {'i': 'hij', 'b': None}]

تعتمد كيف تجمع بين القواميس ثم تعتمد على ما إذا كنت تتوقع أكثر من مباراة واحدة. إذا كنت تريد مباراة واحدة فقط ، فيمكنك القيام بذلك:

>>> results = {}
>>> for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk'):
...     results.update(dict((k,v) for k, v in match.groupdict().iteritems() if v is not None))
... 
>>> results
{'i': 'hij', 'b': 'abc'}

أو لمباريات متعددة:

>>> results = defaultdict(lambda: [])
>>> for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijkabcdefghijk'):
...     for k, v in match.groupdict().iteritems():
...         if v is not None:
...             results[k].append(v)
... 
>>> results
defaultdict(<function <lambda> at 0x7f53d0992c08>, {'i': ['hij', 'hij'], 'b': ['abc', 'abc']})

هذه طريقة لا تتطلب finditer ولا دمج القاموس:

>>> pat = re.compile(r'(?:.*?(?:(?P<b>.b.)|(?P<i>.i.))){2}')

>>> pat.search('abcdefghijk').groupdict()
{'i': 'hij', 'b': 'abc'}

>>> pat.search('aicdefghbjk').groupdict()
{'i': 'aic', 'b': 'hbj'}

هذا يفترض كل واحد من الشخصيات b و i يظهر مرة واحدة بالضبط في السلسلة الخاصة بك ، وإلا:

  • إذا كان أحد الأحرف مفقودة ، فيمكنك استخدامه {,2} بدلاً من {2}.
  • إذا ظهر أحد الشخصيات أكثر من مرة ، فسيقوم البحث باسترداد المظاهرين الأولين أيضاً منهم (على سبيل المثال يمكن أن يجد b مرتين ولا تجد i على الاطلاق).

إليكم قادمًا متأخرًا للعبة في انتقاد واحد ، وهو أمر قابل للقراءة للمبتدئين أيضًا:

>>> dict([(name, re.search(pattern, "abcdefghijk").group())
          for name, pattern in {"b": ".b.", "i": ".i"}.items()])  
{'b': 'abc', 'i': 'hij'}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top