This is a workflow for Editorial, a Markdown and plain text editor for iOS. To download it, you need to view this page on a device that has the app installed.

Description: This script is used as a sub-workflow by some of my others. It must be installed for them to work properly.

Copyright (c) 2017 Duncan MacIntyre

Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THESOFTWARE.

importeditorimportreimportdatetimeimportworkflow# This class represents a template for a string into which single digits would be filled. A regular# expression can be generated to match the template filled with numbers less than, equal to, or# greater than a given number.classNumTemplate:# on initialization# (initialized with one argument, a string with curly brace sets {} indicating where a digit# would go)def__init__(self,given_string):# store a string that the user provides in an attribute called templateself.template=given_string# find the number of curly brace pairs {} in this string, store this in a length attributeself.length=len(re.findall('{}',given_string))# if the string provided by the user has no curly brace pairs {}, raise an errorifself.length<1:raiseValueError('digit locations in template must be specified with {}')# generate a regular expression to match the template filled with numbers less than, equal to,# and/or greater than given values# (called with an argument for each comparison to be made, in the form '<', '=', or '>' followed# by a self.length-digit integer)defre_gen(self,*args):# if no arguments given, raise an erroriflen(args)<1:raiseValueError('NumTemplate.re_gen() requires at least one argument')# all generated regular expressions will be added to this listre_list=[]# for each argument givenforargumentinargs:# if the argument is not a string, raise an erroriftype(argument)isnotstr:raiseTypeError('all arguments for NumTemplate.re_gen() must be strings')# match the argument against a regular expression to make sure it is in the form '<{}', '={}'# or '>{}' where {} is an integer of self.length digits match=re.match('^(<|=|>)([0-9]{'+str(self.length)+'})$',argument)# if this match is unsuccessful, raise an errorifnotmatch:raiseValueError("all arguments for NumTemplate.re_gen() must be strings in the form '<', '=', or '>' followed by a {}-digit integer".format(self.length))# if the argument starts with '<'ifmatch.group(1)=='<':# repeat for self.length times, with an index of iforiinrange(self.length):# if the digit at index i in the number part of the argument is not 0ifint(match.group(2)[i])!=0:# the following code:# 1. gets a list of regular expression strings, each corresponding to one digit:# - there are i integers which match the start of the number part of the argument# - there is one integer in the form [0-<one less than the integer at index i>]# - there are self.length - (i + 1) integers in the form [0-9]# 2. formats this into self.template# 3. appends the resulting regular expression string to re_listre_list.append(self.template.format(*[match.group(2)[j]forjinrange(i)]+['[0-{}]'.format(int(match.group(2)[i])-1)]+['[0-9]'forjinrange(self.length-(i+1))]))# if the argument starts with '='ifmatch.group(1)=='=':# append the number part of the argument, formatted into the template, to re_listre_list.append(self.template.format(*match.group(2)))# if the match starts with '>'ifmatch.group(1)=='>':# repeat for self.length times, with an index of iforiinrange(self.length):# if the digit at index i in the number part of the argument is not 9ifint(match.group(2)[i])!=9:# the following code:# 1. gets a list of regular expression strings, each corresponding to one digit:# - there are i integers which match the start of the number part of the argument# - there is one integer in the form [<one more than the integer at index i>-9]# - there are self.length - (i + 1) integers in the form [0-9]# 2. formats this into self.template# 3. appends the resulting regular expression string to re_listre_list.append(self.template.format(*[match.group(2)[j]forjinrange(i)]+['[{}-9]'.format(int(match.group(2)[i])+1)]+['[0-9]'forjinrange(self.length-(i+1))]))# the following code:# 1. gets re_list, with items seperated by |s, as a regular expression string# (if re_list only has one item, |s are not used)# 2. surrounds this with '(?:' at the beginning and ')' at the end# (this allows the regular expression to be embedded within a larger regular expression# without messing things up, by indicating it as a distinct regular expression)# 3. returns this resulting regular expression stringreturn'(?:'+(re_list[0]iflen(re_list)==1else'|'.join(re_list))+')'