Here you have many options, each with different minuses.
One approach is to use re-rotation, for example (by weekday|by month)*
:
(?P<freq>Weekly)?\s+from (?P<start>.+?)\s+till (?P<end>.+?)(?:\s+by weekday (?P<byweekday>.+?)|\s+by month (?P<bymonth>.+?))*$
This will correspond to the lines of the form week month
and month week
, but also week week
or month week month
, etc.
Another option would be to use lookaheads, for example (?=.*by weekday)?(?=.*by month)?
:
(?P<freq>Weekly)?\s+from (?P<start>.+?)\s+till (?P<end>.+?(?=$| by))(?=.*\s+by weekday (?P<byweekday>.+?(?=$| by))|)(?=.*\s+by month (?P<month>.+?(?=$| by))|)
However, this requires a known delimiter (I used "by") to know how far it can be matched. In addition, it will silently ignore any additional characters (this means that they will correspond to the lines of the form by weekday [some gargabe] by month
).
source share