كيفية جعل المادة الدوار regex؟
سؤال
لنفترض أن لدي ما يلي:
{{Hello | Hi | Hey} {World | Earth} | {وداعا | وداع} {noobs | n3wbz | n00blets}}
وأريد أن يتحول ذلك إلى أي مما يلي:
Hello world
Goodbye noobs
Hi earth
farewell n3wbz
// etc.
الانتباه إلى طريقة تداخل بناء الجملة "الدوران".يمكن أن تكون متداخلة على عمق مليار طبقة لكل ما نعرفه.
يمكنني القيام بذلك بسهولة، إلا أنه بمجرد تداخلها مثل المثال أعلاه، فإن التعبير العادي الخاص بي يفسد والنتائج غير صحيحة.
هل يمكن لشخص ما أن يعرض مثالاً إما بلغة .NET أو Python من فضلك؟
المحلول
طريقة بسيطة مع re.subn, ، والتي يمكنها أيضًا قبول دالة بدلاً من سلسلة بديلة:
import re
from random import randint
def select(m):
choices = m.group(1).split('|')
return choices[randint(0, len(choices)-1)]
def spinner(s):
r = re.compile('{([^{}]*)}')
while True:
s, n = r.subn(select, s)
if n == 0: break
return s.strip()
إنه ببساطة يستبدل جميع الخيارات العميقة التي يقابلها، ثم يتكرر حتى لا يبقى أي خيار. subn
تُرجع صفًا بالنتيجة وعدد الاستبدالات التي تم إجراؤها، وهو أمر مناسب لاكتشاف نهاية المعالجة.
نسختي من select()
يمكن استبداله بـ Bobince الذي يستخدم random.choice()
ويكون أكثر أناقة إذا كنت تريد فقط الالتزام بمحدد عشوائي.إذا كنت ترغب في إنشاء شجرة اختيار، فيمكنك توسيع الوظيفة المذكورة أعلاه، ولكنك ستحتاج إلى متغيرات عامة لتتبع مكانك، لذا فإن نقل الوظائف إلى فئة سيكون منطقيًا.هذا مجرد تلميح، ولن أطور هذه الفكرة لأنه لم يكن السؤال الأصلي حقًا.
لاحظ أخيرًا أنه يجب عليك استخدام r.subn(select, s, re.U)
إذا كنت بحاجة إلى سلاسل Unicode (s = u"{...}"
)
مثال:
>>> s = "{{Hello|Hi|Hey} {world|earth} | {Goodbye|farewell} {noobs|n3wbz|n00blets}}"
>>> print spinner(s)
'farewell n3wbz'
يحرر: تم استبداله sub
بواسطة subn
لتجنب الحلقة اللانهائية (بفضل Bobince للإشارة إليها) وجعلها أكثر كفاءة واستبدالها {([^{}]+)}
بواسطة {([^{}]*)}
لاستخراج الأقواس المتعرجة الفارغة أيضًا.وهذا من شأنه أن يجعله أكثر قوة للأنماط سيئة التنسيق.
بالنسبة للأشخاص الذين يحبون وضع أكبر قدر ممكن في سطر واحد (وهو ما لا أشجعه شخصيًا):
def spin(s):
while True:
s, n = re.subn('{([^{}]*)}',
lambda m: random.choice(m.group(1).split("|")),
s)
if n == 0: break
return s.strip()
نصائح أخرى
ويجب أن تكون بسيطة إلى حد ما، مجرد السماح هدفين تعيينها من بينها آخر، ثم استدعاء مرارا القيام البدلاء من المباريات الداخلية إلى الخارج:
def replacebrace(match):
return random.choice(match.group(1).split('|'))
def randomizebraces(s):
while True:
s1= re.sub(r'\{([^{}]*)\}', replacebrace, s)
if s1==s:
return s
s= s1
>>> randomizebraces('{{Hello|Hi|Hey} {world|earth}|{Goodbye|farewell} {noobs|n3wbz|n00blets}}')
'Hey world'
>>> randomizebraces('{{Hello|Hi|Hey} {world|earth}|{Goodbye|farewell} {noobs|n3wbz|n00blets}}')
'Goodbye noobs'
العاكس التعابير المنطقية الاستخدامات <لأ href = "HTTP: // pyparsing.wikispaces.com/ "يختلط =" نوفولو noreferrer "> pyparsing لتوليد مطابقة السلاسل (مع بعض القيود - حرف التكرار غير محدود مثل + و * لا يسمح). إذا قمت باستبدال {} الصورة مع () الصورة لجعل السلسلة الأصلية الخاصة بك إلى التعابير المنطقية، يولد العاكس لهذه القائمة:
Helloworld
Helloearth
Hiworld
Hiearth
Heyworld
Heyearth
Goodbyenoobs
Goodbyen3wbz
Goodbyen00blets
farewellnoobs
farewelln3wbz
farewelln00blets
(وأنا أعلم وانهار المساحات، ولكن ربما هذا الرمز سوف اعطيكم بعض الأفكار حول كيفية مهاجمة هذه المشكلة.)
وأود أن استخدام re.finditer وبناء شجرة تحليل الأساسية لتحديد مستوى التداخل. للقيام بذلك، وأود أن استخدام السمة مدى الكائن يتطابق مع التعبير العادي:
text = '{{Hello|Hi|Hey} {world|earth} | {Goodbye|farewell} {noobs|n3wbz|n00blets}}'
import re
re_bracks = re.compile(r'{.+?}')
# subclass list for a basic tree datatype
class bracks(list):
def __init__(self, m):
self.m = m
# icky procedure to create the parse tree
# I hate these but don't know how else to do it
parse_tree = []
for m in re_bracks.finditer(text):
if not this_element:
# this first match
parse_tree.extend(element(m))
else:
# ... and all the rest
this_element = bracks(m)
this_start, this_end = m.span()
# if this match is nested in the old one ...
if this_start < previous_start and this_end > previous_end:
# nest it inside the previous one
previous_element.extend(this_element)
else:
# otherwise make it a child of the parse_tree
parse_tree.extend(element(m))
previous_element = this_element
previous_start, previous_end = this_start, this_end
وهذا من شأنه أن تعطيك عمق التعشيش من التعبيرات بين قوسين. إضافة بعض منطق مماثل لأنابيب وكنت يكون جيدا على طريقك إلى حل المشكلة.
وأنا أوصي أن نلقي نظرة على محرك دادا للحصول على الإلهام.
ولقد فعلت لتنفيذ شيء مستوحاة من هذا في مخطط وAST مخطط الاستدانة في التعبير عن احتياجاتي.
وعلى وجه التحديد، أنصح بقوة ضد محاولة استخدام التعابير المنطقية كما محلل بشكل عام.