├── spintax ├── __init__.py └── spintax.py ├── examples ├── super_hero_name_generator.py ├── super_hero_greeting.py └── simple_password_generator.py ├── .gitattributes ├── LICENCE ├── setup.py ├── .gitignore ├── tests └── spintax_tests.py └── README.md /spintax/__init__.py: -------------------------------------------------------------------------------- 1 | from .spintax import spin, parse 2 | -------------------------------------------------------------------------------- /examples/super_hero_name_generator.py: -------------------------------------------------------------------------------- 1 | import spintax 2 | 3 | 4 | # Function to generate the super hero name 5 | def GenerateSuperHeroName(): 6 | SuperHeroName = spintax.spin(r"{The |}{Super|Scarlet|Commander|Hydro|Captain|Fantastic|Colossal|Nighthawk|Wild} {Mountain|Hawk|Flame|Claw|Machine|Watchman}") 7 | return SuperHeroName 8 | 9 | # Only print name if it is run directly 10 | if __name__ == "__main__": 11 | print(GenerateSuperHeroName()) 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /examples/super_hero_greeting.py: -------------------------------------------------------------------------------- 1 | import spintax 2 | import super_hero_name_generator 3 | 4 | # Generate Super hero name 5 | SuperHeroName = super_hero_name_generator.GenerateSuperHeroName() 6 | 7 | # Generate greeting 8 | SuperHeroText = r""" 9 | {Hello|Hi|Hey}{,|} I{'| a}m \{0\}{,|!|!!!} 10 | I {{come|am} {here|on this earth}|{came|travelled} {here|to this place}} to {protect|save} {humanity|the world|humans|civilization} {and {destroy|kill|eradicate|remove}|by {destroy|kill|eradicat|remov}ing} all {evil|badness|hate}. 11 | """ 12 | # As the { and } were escaped this allowed us to use .format() to insert the name 13 | print(spintax.spin(SuperHeroText).format(SuperHeroName)) 14 | -------------------------------------------------------------------------------- /examples/simple_password_generator.py: -------------------------------------------------------------------------------- 1 | import spintax 2 | # Don't use this it is not secure it is only an example 3 | # Only 470,400 possible unique combinations 4 | 5 | 6 | # Function to generate password 7 | def GenerateSuperHeroName(): 8 | SuperHeroName = spintax.spin(r"{The|One|A|}{Big|Large|Small|Tiny|Giant|Titanic|Massive}{Blue|Red|Green|Yellow|Purple|Violet|Rose|Black|White|Pink}{Dog|Cat|Pig|Cow|Chicken|Rabbit|Sheep|Duck|Goat|Elephant}{Is|IsNow|HasBeen|Was|WasJust|}{Happily|Gladly|Joyfully|}{Eating|Jumping|Running|Walking|Smiling|Playing|Laughing}") 9 | return SuperHeroName 10 | 11 | # Only print password if it is run directly 12 | if __name__ == "__main__": 13 | print(GenerateSuperHeroName()) 14 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | spintax, a Python module for parsing spintax, unlike any other modules this also allows the user to escape the special characters used in its syntax. 2 | Copyright (C) 2015 Alexander Lewis 3 | http://www.AceLewis.com 4 | https://github.com/AceLewis 5 | https://github.com/AceLewis/spintax 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | 19 | Contact: 20 | Twitter: @_AceLewis -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup(name='spintax', 4 | version='1.0.4', 5 | description='A Python module for parsing spintax', 6 | long_description='A Python module for parsing spintax, unlike any other module this works with nested spintax and also allows the user to escape the special characters used in its syntax.', 7 | keywords=['spintax', 'spin syntax', 'spintax parser', 'spinning', 'spin'], 8 | url='http://github.com/AceLewis/spintax', 9 | download_url='https://github.com/AceLewis/spintax/archive/master.zip', 10 | author='AceLewis', 11 | license='GPLv3', 12 | packages=['spintax'], 13 | classifiers=[ 14 | 'Programming Language :: Python', 15 | 'Programming Language :: Python :: 2', 16 | 'Programming Language :: Python :: 3', 17 | 'Operating System :: OS Independent', 18 | 'Topic :: Text Processing', 19 | 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 20 | ], 21 | zip_safe=False) 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | spintax.egg-info/PKG-INFO 45 | *.txt 46 | spintax/__pycache__/__init__.cpython-34.pyc 47 | *.pyc 48 | dist/spintax-0.1-py3.4.egg 49 | spintax.egg-info/not-zip-safe 50 | build/lib/spintax/__init__.py 51 | *.pypirc 52 | dist/spintax-0.1.zip 53 | dist/spintax-0.1-py3-none-any.whl 54 | 55 | # OTHER 56 | 57 | .idea* 58 | dist/* 59 | build/* 60 | -------------------------------------------------------------------------------- /tests/spintax_tests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | # Change directory to import the Spintax module 4 | import sys 5 | from os import path 6 | testdir = path.dirname(__file__) 7 | srcdir = '../spintax/' 8 | sys.path.insert(0, path.abspath(path.join(testdir, srcdir))) 9 | 10 | import spintax 11 | 12 | 13 | class TestSpintax(unittest.TestCase): 14 | def test_nothing(self): 15 | self.assertEqual(spintax.spin('nothing'), 'nothing') 16 | 17 | def test_simple(self): 18 | self.assertIn(spintax.spin('{Hello|Hi}'), ['Hello', 'Hi']) 19 | 20 | def test_nested(self): 21 | self.assertIn(spintax.spin('{{Hello|Hi}|{Hey|Yo}}'), 22 | ['Hello', 'Hi', 'Hey', 'Yo']) 23 | 24 | def test_escaped(self): 25 | self.assertEqual(spintax.spin(r'\{test}'), r'{test}') 26 | 27 | def test_not_escaped(self): 28 | self.assertEqual(spintax.spin(r'\\{test}'), r'\test') 29 | 30 | def test_escaped_with_backslash(self): 31 | self.assertEqual(spintax.spin(r'\\\{test}'), r'\{test}') 32 | 33 | def test_escaped_seperator(self): 34 | self.assertEqual(spintax.spin('{Hello\|Hi}'), r'Hello|Hi') 35 | 36 | def test_not_escaped_seperator(self): 37 | self.assertIn(spintax.spin(r'{Hello\\|Hi}'), ['Hello\\', 'Hi']) 38 | 39 | def test_escaped_seperator_with_backslash(self): 40 | self.assertEqual(spintax.spin(r'{Hello\\\|Hi}'), r'Hello\|Hi') 41 | 42 | def test_newline(self): 43 | set_up = set([spintax.spin("{a\n|b\n}") for a in range(50)]) 44 | self.assertEqual(set_up, {'b\n', 'a\n'}) 45 | 46 | def test_escaped_pipe_at_end(self): 47 | set_up = set([spintax.spin("{a\||b\|}") for a in range(50)]) 48 | self.assertEqual(set_up, {'b|', 'a|'}) 49 | 50 | def test_escaped_at_end(self): 51 | set_up = set([spintax.spin(r"{|a\\}") for a in range(50)]) 52 | self.assertEqual(set_up, {'', 'a\\'}) 53 | 54 | def test_escaped_at_end_only_one(self): 55 | set_up = set([spintax.spin(r"{a\\}") for a in range(50)]) 56 | self.assertEqual(set_up, {'a\\'}) 57 | 58 | 59 | if __name__ == '__main__': 60 | unittest.main() 61 | -------------------------------------------------------------------------------- /spintax/spintax.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | import random 4 | # Import warnings and enable DeprecationWarning's for parse function 5 | import warnings 6 | warnings.simplefilter('always', DeprecationWarning) 7 | 8 | if sys.version_info[0] == 2: 9 | # If Python 2 use unicode character conversion 10 | chr = unichr 11 | 12 | def _replace_string(match): 13 | """ 14 | Function to replace the spintax with a randomly chosen string 15 | :param match object: 16 | :return string: 17 | """ 18 | global spintax_seperator, random_string 19 | test_string = re.sub(spintax_seperator, lambda x: x.group(1)+random_string, match.group(2)) 20 | split_strings = re.split(random_string, test_string) 21 | random_picked = random.choice(split_strings) 22 | return match.group(1) + random_picked + ['', match.group(3)][random_picked==split_strings[-1]] 23 | 24 | 25 | def spin(string, seed=None): 26 | """ 27 | Function used to spin the spintax string 28 | :param string: 29 | :param seed: 30 | :return string: 31 | """ 32 | 33 | # As look behinds have to be a fixed width I need to do a "hack" where 34 | # a temporary string is used. This string is randomly chosen. There are 35 | # 1.9e62 possibilities for the random string and it uses uncommon Unicode 36 | # characters, that is more possibilerties than number of Planck times that 37 | # have passed in the universe so it is safe to do. 38 | characters = [chr(x) for x in range(1234, 1368)] 39 | global random_string 40 | random_string = ''.join(random.sample(characters, 30)) 41 | 42 | # If the user has chosen a seed for the random numbers use it 43 | random.seed(seed) 44 | 45 | # Regex to find spintax seperator, defined here so it is not re-defined 46 | # on every call to _replace_string function 47 | global spintax_seperator 48 | spintax_seperator = r'((?:(?