Editorial Workflows

Custom Classes and Functions

public workflow

Install Workflow...

This workflow contains at least one Python script. Only use it if you trust the person who shared this with you, and if you know exactly what it does.

I understand, install the workflow!

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 copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

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

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, 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 THE
SOFTWARE.

Shared by: Duncan MacIntyre

Comments: Comment Feed (RSS)

There are no comments yet.

+ Add Comment

Workflow Preview
Run Python Script ?
Source Code
import editor
import re
import datetime
import workflow

# 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.
class NumTemplate:
	# 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 template
		self.template = given_string
		# find the number of curly brace pairs {} in this string, store this in a length attribute
		self.length = len(re.findall('{}', given_string))
		
		# if the string provided by the user has no curly brace pairs {}, raise an error
		if self.length < 1:
			raise ValueError('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)
	def re_gen(self, *args):
		# if no arguments given, raise an error
		if len(args) < 1:
			raise ValueError('NumTemplate.re_gen() requires at least one argument')
		
		# all generated regular expressions will be added to this list
		re_list = []
		
		# for each argument given
		for argument in args:
			# if the argument is not a string, raise an error
			if type(argument) is not str:
				raise TypeError('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 error
			if not match:
				raise ValueError("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 '<'
			if match.group(1) == '<':
				# repeat for self.length times, with an index of i
				for i in range(self.length):
					# if the digit at index i in the number part of the argument is not 0
					if int(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_list
						re_list.append(self.template.format(*
							[match.group(2)[j] for j in range(i)] +
							['[0-{}]'.format(int(match.group(2)[i]) - 1)] + 
							['[0-9]' for j in range(self.length - (i + 1))]
						))
			
			# if the argument starts with '='
			if match.group(1) == '=':
				# append the number part of the argument, formatted into the template, to re_list
				re_list.append(self.template.format(*match.group(2)))
			
			# if the match starts with '>'
			if match.group(1) == '>':
				# repeat for self.length times, with an index of i
				for i in range(self.length):
					# if the digit at index i in the number part of the argument is not 9
					if int(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_list
						re_list.append(self.template.format(*
							[match.group(2)[j] for j in range(i)] +
							['[{}-9]'.format(int(match.group(2)[i]) + 1)] +
							['[0-9]' for j in range(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 string
		return '(?:' + (re_list[0] if len(re_list) == 1 else '|'.join(re_list)) + ')'