├── .gitignore ├── CHANGELOG ├── LICENSE ├── README ├── scriptures ├── __init__.py ├── bible_re.py ├── references.py ├── tests │ ├── __init__.py │ ├── test_1611_booknames.py │ ├── test_deuterocanon_booknames.py │ ├── test_normalization.py │ ├── test_protestant_booknames.py │ └── test_reference_to_string.py └── texts │ ├── __init__.py │ ├── base.py │ ├── deuterocanon.py │ ├── kjv1611.py │ └── protestant.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | 3 | *~ 4 | *.pyc 5 | *.swp 6 | /env/ 7 | /build/ 8 | 9 | MANIFEST 10 | /dist/ 11 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 1.0.0 (2011-11-24) - Initial Release 2 | ==================================== 3 | 4 | * python-scriptures is a Python package and regular expression library for 5 | validating, extracting, and normalizing biblical scripture references from 6 | blocks of text. 7 | 8 | 1.0.1 (2011-11-25) - Doc Fix 9 | ============================ 10 | 11 | * Fixed documentation error in README 12 | 13 | 1.1.0 (2012-03-31) - Single Chapter Books 14 | ========================================= 15 | 16 | * Updated scripture reference regex to recognize an end chapter and verse even 17 | if no start verse is provided 18 | 19 | * Added special case reference normalization for single chapter books 20 | 21 | * Broke scripture_re regex into multiple lines for better legibility 22 | 23 | * Updated documentation to explain single chapter book extraction 24 | 25 | * Rewrote reference_to_string and provided better output for single chapter book 26 | references 27 | 28 | * Added single chapter book reference_to_string examples to documentation 29 | 30 | 1.1.1 (2013-04-01) - Regex Fix 31 | ============================== 32 | 33 | * Updated scripture reference regex to require a word boundry before the book title 34 | 35 | 1.1.2 (2013-05-03) - Obadiah Regex Fix 36 | ====================================== 37 | 38 | * Fixed Obadiah book name regular expression - Thank you Ben McFadden (mcfadden) 39 | 40 | 1.1.3 (2014-04-05) - Psalms Regex Fix 41 | ===================================== 42 | 43 | * Psalms regular expression now recognizes "Psalms" in addition to "Ps", "Psa", "Psalm". 44 | 45 | 2.0.0 (2014-04-05) - Python 3 Compatibility 46 | =========================================== 47 | 48 | * Made some simple adjustments so that python-scriptures now works with python 3. 49 | - module imports now use relative import syntax 50 | - use .values() on small dict instead of .itervalues() 51 | 52 | 2.1.0 (2014-05-08) - Unicode Compatibility and Bugfixes 53 | ======================================================= 54 | 55 | * Made the library unicode compatible with the ability to recognize the \u2013 en and \u2014 em dashes 56 | * Added the OSIS Phlm abbreviation to the Philemon regex 57 | * Fixed a regex book matching bug that was causing Philemon references to match as Philippians (Thank you Ganon11 for the bug report) 58 | 59 | 2.1.2 (2015-03-18) - Multi-Chapter references 60 | ============================================= 61 | 62 | * Can now reference multiple chapters 63 | - ex: Revelation 2-3 64 | 65 | 2.1.3 (2015-03-19) - Print Debug Msg 66 | ==================================== 67 | 68 | * Removed print debug msg 69 | 70 | 2.2.0 (2015-03-20) - Test Suite, Better Output, Better Book Variant Matching 71 | ============================================================================ 72 | 73 | * Added a full test suite to verify 74 | - chapter and verse style normalization 75 | - output formatting 76 | - book names and abbreviations 77 | * Added multi-chapter output format (ex. John 1:1-2:25 will yield John 1-2) 78 | * Updated book regular expressions 79 | - added Eccles for Ecclesiasates 80 | - added Chron abbreviation for I and II Chronicles (ex. I Chron) 81 | - added Philem for Philemon 82 | - added Jon for Jonah 83 | - added Song of Sol for Song of Solomon 84 | 85 | 2.2.1 (2015-06-27) - Added new format: book ch-ech:ev 86 | ===================================================== 87 | * Thanks to @mpnordland for the bug report and feature request 88 | - I Sam 28-28:2 format now works as expected 89 | - Multichapter references in this format such as I Sam 28-29:2 also work 90 | 91 | 3.0.0 (2016-12-29) - New Text Implementation 92 | ============================================ 93 | * Adds ability to easily extend Texts (Create new Texts) 94 | * Provides additional texts as part of the library 95 | - Protestant Bible 96 | - King James 1611 97 | - Deuterocanon 98 | * Thanks to @aletheist, @strawhead, @JeffMelton, @mlv for helping with this release! 99 | 100 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2015, David Davis 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | * Neither the name of the copyright holder nor the names of its contributors 13 | may be used to endorse or promote products derived from this software without 14 | specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ================= 2 | Python Scriptures 3 | ================= 4 | 5 | python-scriptures is a Python 2 and Python 3 compatible package and regular 6 | expression library for validating, extracting and normalizing biblical 7 | scripture references from blocks of text. 8 | 9 | For more information, see http://www.davisd.com/projects/python-scriptures/ 10 | 11 | Typical usage is as follows:: 12 | 13 | #!/usr/bin/env python 14 | 15 | >>> import scriptures 16 | >>> scriptures.extract('This is a test Rom 3:23-28 and 1 JOHn 2') 17 | [('Romans', 3, 23, 3, 28), ('I John', 2, 1, 2, 29)] 18 | 19 | Range validation is performed automatically and invalid references are not 20 | extracted. 21 | 22 | >>> import scriptures 23 | >>> scriptures.extract('Romans 3:23 is real, but Romans 2:30 is invalid.') 24 | [('Romans', 3, 23, 3, 23)] 25 | 26 | Multi-Chapter references work: 27 | 28 | >>> import scriptures 29 | >>> scriptures.extract('You can specify a range of chapters like Rev 2-3') 30 | [('Revelation of Jesus Christ', 2, 1, 3, 22)] 31 | 32 | References with single chapter books do not require the chapter be specified. 33 | 34 | >>> import scriptures 35 | >>> scriptures.extract('You can specify a single verse such as Jude 4') 36 | [('Jude', 1, 4, 1, 4)] 37 | >>> scriptures.extract('Or specify multiple verses with jude 2-5...') 38 | [('Jude', 1, 2, 1, 5)] 39 | 40 | 41 | Installation 42 | ============ 43 | 44 | A setup script (setup.py) is provided. To install, simply run the script with 45 | the install command: 46 | 47 | $ python setup.py install 48 | 49 | Or just put the scriptures package somewhere on the Python path. 50 | 51 | 52 | API 53 | === 54 | 55 | Return Values 56 | ------------- 57 | 58 | When a "scripture reference" is returned, it is always a five value tuple 59 | consisting of: 60 | 61 | ('Book name', start chapter, start verse, end chapter, end verse) 62 | 63 | 64 | Functions 65 | --------- 66 | 67 | There are four public functions exposed by this package. 68 | 69 | extract 70 | ~~~~~~~ 71 | 72 | Extract a list of tupled scripture references from a block of text. 73 | 74 | Arguments: 75 | 76 | text -- the block of text containing potential scripture references 77 | 78 | Example: 79 | 80 | >>> import scriptures 81 | >>> scriptures.extract('This is a test Rom 3:23-28 and 1 JOHn 2') 82 | [('Romans', 3, 23, 3, 28), ('I John', 2, 1, 2, 29)] 83 | 84 | 85 | reference_to_string 86 | ~~~~~~~~~~~~~~~~~~~ 87 | 88 | Get a display friendly string from a scripture reference. 89 | 90 | Arguments: 91 | 92 | bookname -- the full or abbreviated book name 93 | 94 | chapter -- the starting chapter 95 | 96 | Optional Arguments: 97 | 98 | verse -- the starting verse 99 | 100 | end_chapter -- the ending chapter 101 | 102 | end_verse -- the ending verse 103 | 104 | Examples: 105 | 106 | >>> import scriptures 107 | >>> scriptures.reference_to_string('acts', 1) 108 | 'Acts 1' 109 | >>> scriptures.reference_to_string('John', 3, 16) 110 | 'John 3:16' 111 | >>> scriptures.reference_to_string('Rom', 3, 23, 3, 28) 112 | 'Romans 3:23-28' 113 | >>> scriptures.reference_to_string('ecc', 1, 2, 2) 114 | 'Ecclesiastes 1:2-2:26' 115 | >>> scriptures.reference_to_string('john', 1, 1, 2, 25) 116 | 'John 1-2' 117 | 118 | Single Chapter Book Examples: 119 | 120 | >>> import scriptures 121 | >>> scriptures.reference_to_string('jude', 1, 4) 122 | 'Jude 4' 123 | >>> scriptures.reference_to_string('2john', 1, 4, 1, 7) 124 | 'II John 4-7' 125 | 126 | 127 | normalize_reference 128 | ~~~~~~~~~~~~~~~~~~~ 129 | 130 | Get a complete five value tuple scripture reference with full book name from 131 | partial data. 132 | 133 | Arguments: 134 | 135 | bookname -- the full or abbreviated book name 136 | 137 | chapter -- the starting chapter 138 | 139 | Optional Arguments: 140 | 141 | verse -- the starting verse 142 | 143 | end_chapter -- the ending chapter 144 | 145 | end_verse -- the ending verse 146 | 147 | Examples: 148 | 149 | >>> import scriptures 150 | >>> scriptures.normalize_reference('acts', 1) 151 | ('Acts', 1, 1, 1, 26) 152 | >>> scriptures.normalize_reference('John', 3, 16) 153 | ('John', 3, 16, 3, 16) 154 | >>> scriptures.normalize_reference('Rom', 3, 23, 3, 28) 155 | ('Romans', 3, 23, 3, 28) 156 | >>> scriptures.normalize_reference('ecc', 1, 2, 2) 157 | ('Ecclesiastes', 1, 2, 2, 26) 158 | 159 | 160 | is_valid_reference 161 | ~~~~~~~~~~~~~~~~~~ 162 | 163 | Check to see if a scripture reference is valid. 164 | 165 | Arguments: 166 | 167 | bookname -- the full or abbreviated book name 168 | 169 | chapter -- the starting chapter 170 | 171 | Optional Arguments: 172 | 173 | verse -- the starting verse 174 | 175 | end_chapter -- the ending chapter 176 | 177 | end_verse -- the ending verse 178 | 179 | Examples: 180 | 181 | >>> import scriptures 182 | >>> scriptures.is_valid_reference('John', 3, 16) 183 | True 184 | >>> scriptures.is_valid_reference('ecc', 1, 2, 2) 185 | True 186 | >>> scriptures.is_valid_reference('Romans', 2, 30) 187 | False 188 | >>> scriptures.is_valid_reference('Romans', 2, 20, 2, 29) 189 | True 190 | 191 | 192 | Regular Expressions 193 | ------------------- 194 | 195 | There are two compiled regular expression patterns exposed by this package. 196 | 197 | book_re 198 | ~~~~~~~ 199 | 200 | Match a valid abbreviation or book name. 201 | 202 | Examples: 203 | 204 | >>> import scriptures 205 | >>> import re 206 | >>> re.findall(scriptures.book_re, 'Matt test Ecclesiastes and 2 peter') 207 | ['Matt', 'Ecclesiastes', '2 peter'] 208 | 209 | 210 | scripture_re 211 | ~~~~~~~~~~~~ 212 | 213 | Match a scripture reference pattern from a valid abbreviation or book name. 214 | 215 | Examples: 216 | 217 | >>> import scriptures 218 | >>> import re 219 | >>> re.findall(scriptures.scripture_re, 'Matt 3 & Acts 1:2-3 Rev 2:1-3:2') 220 | [('Matt', '3', '', '', ''), ('Acts', '1', '2', '', '3'), 221 | ('Rev', '2', '1', '3', '2')] 222 | 223 | 224 | Unicode 225 | ======= 226 | 227 | This library is unicode compatible and recognizes the \u2013 en dash and \u2014 228 | em dash. 229 | 230 | 231 | Additional Texts 232 | ================ 233 | 234 | This library currently provides the following texts: 235 | 236 | * protestant - scriptures.texts.protestant.ProtestantCanon 237 | * deuterocanon - scriptures.texts.deutercanon.Deuterocanon 238 | * kjv1611 - scriptures.texts.kjv1611.KingJames1611 239 | 240 | Usage 241 | ----- 242 | 243 | To use the additional texts, simply instantiate the text object and use the api 244 | functions and regular expressions on the new instance. 245 | 246 | Example 247 | ~~~~~~~ 248 | 249 | >>> from scriptures.texts.kjv1611 import KingJames1611 250 | >>> myKJV1611 = KingJames1611() 251 | >>> myKJV1611.extract('the protestant books are implemented- Matthew 1:1-5') 252 | [(u'Matthew', 1, 1, 1, 5)] 253 | >>> myKJV1611.extract('and Deuterocanon (apocrypha)- wisdom of solomon 1:1') 254 | [(u'The Wisdom of Solomon', 1, 1, 1, 1)] 255 | >>> myKJV1611.extract('and I Esd 1:1, II Esd 1:1, Prayer of Manasseh 1:1') 256 | [(u'I Esdras', 1, 1, 1, 1), (u'II Esdras', 1, 1, 1, 1), (u'Prayer of Manasseh', 1, 1, 1, 1)] 257 | 258 | 259 | Custom Texts 260 | ============ 261 | 262 | As of v3.0.0, the library makes makes extending the library through custom texts 263 | trivial through additional modules. Please consider contributing your text 264 | modules to this project by creating texts under scriptures/texts/ and submitting 265 | a pull request. 266 | 267 | 268 | Creating a New Text 269 | ------------------- 270 | 271 | To create a new Text, 272 | 273 | 1) Create a class that inherits from scriptures.base.Text 274 | 2) Implement the "books" dictionary 275 | 3) Instantiate your new text and use it 276 | 277 | The four api functions will be available from your instance: 278 | 279 | * extract 280 | * reference_to_string 281 | * normalize_reference 282 | * is_valid_reference 283 | 284 | The two regular expressions are also available: 285 | 286 | * book_re 287 | * scripture_re 288 | 289 | 290 | Example 291 | ~~~~~~~ 292 | 293 | >>> from scriptures.texts.base import Text 294 | >>> class MyText(Text): 295 | >>> books = { 296 | >>> 'test1': ('Test Book 1', 'TBook1', 'test(?:\s)?1', [5, 4, 3, 4, 5]), 297 | >>> 'test2': ('Test Book 2', 'TBook2', 'test(?:\s)?2', [5, 4, 3, 4, 5]) 298 | >>> } 299 | >>> 300 | >>> mytext = MyText() 301 | >>> mytext.extract('Ok, testing- test1 1:3-5 and test2 2:4') 302 | [('Test Book 1', 1, 3, 1, 5), ('Test Book 2', 2, 4, 2, 4)] 303 | 304 | 305 | Creating a New Text Using Another As a Starting Point 306 | ----------------------------------------------------- 307 | 308 | If you would like to use an existing set of books as a starting point, simply 309 | update your books dictionary using the books from the Text class (or classes) 310 | that you'd like to use as a starting point. 311 | 312 | For an example of this, see the "KingJames1611" text class in 313 | scriptures/text/kjv1611.py 314 | 315 | The KingJames1611 Text class uses the ProtestantCanon and Deuterocanon books as 316 | a starting point and adds I Esdras, II Esdras, and the Prayer of Manasseh. 317 | 318 | Test Suite 319 | ========== 320 | 321 | Unit tests are provided to verify chapter and verse style normalization, output 322 | formatting, and book names and abbreviations. 323 | 324 | To run the test suite, cwd to just outside of the scriptures package and: 325 | 326 | $ python -m unittest discover 327 | 328 | 329 | Author 330 | ====== 331 | 332 | David Davis 333 | http://www.davisd.com 334 | 335 | -------------------------------------------------------------------------------- /scriptures/__init__.py: -------------------------------------------------------------------------------- 1 | from .bible_re import book_re, scripture_re 2 | 3 | from .references import extract, reference_to_string, \ 4 | normalize_reference, is_valid_reference 5 | 6 | -------------------------------------------------------------------------------- /scriptures/bible_re.py: -------------------------------------------------------------------------------- 1 | from .texts.protestant import ProtestantCanon 2 | 3 | # create an instance of the Protestant Canon to use as the default 4 | pcanon=ProtestantCanon() 5 | 6 | book_re = pcanon.book_re 7 | scripture_re = pcanon.scripture_re 8 | 9 | -------------------------------------------------------------------------------- /scriptures/references.py: -------------------------------------------------------------------------------- 1 | from .bible_re import pcanon 2 | from .texts import InvalidReferenceException 3 | 4 | # The functions below are shortcut-functions to the ProtestantCanon text 5 | # The same functions could be verbosely accessed with: 6 | # 7 | # >>> from scriptures.texts.protestant import ProtestantCanon 8 | # >>> pc=ProtestantCanon() 9 | # 10 | # The instance variable "pc" has the functions: get_book, extract, 11 | # is_valid_reference, reference_to_string, and normalize_reference 12 | # 13 | # For instructions on using a different Text, see the documentation 14 | 15 | def get_book(name): 16 | """ 17 | Get a book from its name or None if not found 18 | """ 19 | return pcanon.get_book(name) 20 | 21 | def extract(text): 22 | """ 23 | Extract a list of tupled scripture references from a block of text 24 | """ 25 | return pcanon.extract(text) 26 | 27 | def is_valid_reference(bookname, chapter, verse=None, 28 | end_chapter=None, end_verse=None): 29 | """ 30 | Check to see if a scripture reference is valid 31 | """ 32 | return pcanon.is_valid_reference(bookname, chapter, verse, end_chapter, 33 | end_verse) 34 | 35 | def reference_to_string(bookname, chapter, verse=None, 36 | end_chapter=None, end_verse=None): 37 | """ 38 | Get a display friendly string from a scripture reference 39 | """ 40 | return pcanon.reference_to_string(bookname, chapter, verse, 41 | end_chapter, end_verse) 42 | 43 | def normalize_reference(bookname, chapter, verse=None, 44 | end_chapter=None, end_verse=None): 45 | """ 46 | Get a complete five value tuple scripture reference with full book name 47 | from partial data 48 | """ 49 | return pcanon.normalize_reference(bookname, chapter, verse, end_chapter, 50 | end_verse) 51 | 52 | -------------------------------------------------------------------------------- /scriptures/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davisd/python-scriptures/25639d5696c3d007cdf00844f0a499810daad80c/scriptures/tests/__init__.py -------------------------------------------------------------------------------- /scriptures/tests/test_1611_booknames.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from ..texts.kjv1611 import KingJames1611 4 | 5 | kjv1611 = KingJames1611() 6 | 7 | 8 | def f(txt): 9 | """ 10 | accept a string containing a scripture reference, normalize it, and then 11 | return the reformatted string 12 | """ 13 | return kjv1611.reference_to_string( 14 | *kjv1611.normalize_reference(*kjv1611.scripture_re.match(txt).groups())) 15 | 16 | 17 | class Test1611BookNames(unittest.TestCase): 18 | def setUp(self): 19 | pass 20 | 21 | # A single old testament book - proves the 1611 is pulling in OT texts 22 | def test_genesis(self): 23 | self.assertEqual(f('genesis 1:1'), 'Genesis 1:1') 24 | self.assertEqual(f('gen 1:1'), 'Genesis 1:1') 25 | 26 | # /Old Testament 27 | 28 | # New Testament 29 | 30 | # A single new testament book - proves the 1611 is pulling in NT texts 31 | def test_matthew(self): 32 | self.assertEqual(f('matthew 1:1'), 'Matthew 1:1') 33 | self.assertEqual(f('matt 1:1'), 'Matthew 1:1') 34 | 35 | # /New Testament 36 | 37 | # Apocryphal Books 38 | 39 | def test_i_esdras(self): 40 | self.assertEqual(f('I esdras 1:1'), 'I Esdras 1:1') 41 | self.assertEqual(f('1 esdras 1:1'), 'I Esdras 1:1') 42 | self.assertEqual(f('1 esd 1:1'), 'I Esdras 1:1') 43 | 44 | def test_ii_esdras(self): 45 | self.assertEqual(f('II esdras 1:1'), 'II Esdras 1:1') 46 | self.assertEqual(f('2 esdras 1:1'), 'II Esdras 1:1') 47 | self.assertEqual(f('2 esd 1:1'), 'II Esdras 1:1') 48 | 49 | def test_prayer_of_manasseh(self): 50 | self.assertEqual(f('prayer of manasseh 1'), 'Prayer of Manasseh 1') 51 | self.assertEqual(f('manasseh 1'), 'Prayer of Manasseh 1') 52 | self.assertEqual(f('prman 1'), 'Prayer of Manasseh 1') 53 | 54 | # A single deutoronomical book - just to prove the 1611 55 | # is pulling in deutorocanon texts 56 | def test_tobit(self): 57 | self.assertEqual(f('tobit 1:1'), 'Tobit 1:1') 58 | self.assertEqual(f('tob 1:1'), 'Tobit 1:1') 59 | 60 | # The remaining Deutoronimcal books are tested in the test_deutoronocanon_booknames 61 | 62 | # /Apocryphal Books 63 | 64 | -------------------------------------------------------------------------------- /scriptures/tests/test_deuterocanon_booknames.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from ..texts.deuterocanon import Deuterocanon 4 | 5 | dc = Deuterocanon() 6 | 7 | 8 | def f(txt): 9 | """ 10 | accept a string containing a scripture reference, normalize it, and then 11 | return the reformatted string 12 | """ 13 | return dc.reference_to_string( 14 | *dc.normalize_reference(*dc.scripture_re.match(txt).groups())) 15 | 16 | 17 | class TestDeuterocanonBookNames(unittest.TestCase): 18 | def setUp(self): 19 | pass 20 | 21 | def test_tobit(self): 22 | self.assertEqual(f('tobit 1:1'), 'Tobit 1:1') 23 | self.assertEqual(f('tob 1:1'), 'Tobit 1:1') 24 | 25 | def test_judith(self): 26 | self.assertEqual(f('judith 1:1'), 'Judith 1:1') 27 | self.assertEqual(f('Jud 1:1'), 'Judith 1:1') 28 | 29 | def test_additions_to_esther(self): 30 | self.assertEqual(f('esther (greek) 1:1'), 'Additions to Esther 1:1') 31 | self.assertEqual(f('additions to esther 1:1'), 'Additions to Esther 1:1') 32 | self.assertEqual(f('rest of esther 1:1'), 'Additions to Esther 1:1') 33 | self.assertEqual(f('addesth 1:1'), 'Additions to Esther 1:1') 34 | 35 | def test_wisdom_of_solomon(self): 36 | self.assertEqual(f('the wisdom of solomon 1:1'), 37 | 'The Wisdom of Solomon 1:1') 38 | self.assertEqual(f('wis 1:1'), 'The Wisdom of Solomon 1:1') 39 | self.assertEqual(f('wisdom of solomon 1:1'), 40 | 'The Wisdom of Solomon 1:1') 41 | self.assertEqual(f('wisdom 1:1'), 42 | 'The Wisdom of Solomon 1:1') 43 | 44 | def test_ecclesiasticus_aka_sirach(self): 45 | self.assertEqual(f('sirach 1:1'), 'Sirach 1:1') 46 | self.assertEqual(f('sir 1:1'), 'Sirach 1:1') 47 | self.assertEqual(f('ecclesiasticus 1:1'), 'Sirach 1:1') 48 | 49 | def test_baruch(self): 50 | self.assertEqual(f('baruch 1:1'), 'Baruch 1:1') 51 | self.assertEqual(f('bar 1:1'), 'Baruch 1:1') 52 | 53 | def test_letter_of_jeremiah(self): 54 | self.assertEqual(f('letter of jeremiah 1'), 'Letter of Jeremiah 1') 55 | self.assertEqual(f('epjer 1'), 'Letter of Jeremiah 1') 56 | 57 | def testprayer_of_azariah(self): 58 | self.assertEqual(f('prayer of azariah 1'), 'Prayer of Azariah 1') 59 | self.assertEqual(f('azar 1'), 'Prayer of Azariah 1') 60 | self.assertEqual(f('prazar 1'), 'Prayer of Azariah 1') 61 | self.assertEqual(f('song of the three children 1'), 'Prayer of Azariah 1') 62 | self.assertEqual(f('song of three children 1'), 'Prayer of Azariah 1') 63 | 64 | def test_susanna(self): 65 | self.assertEqual(f('susanna 1'), 'Susanna 1') 66 | self.assertEqual(f('sus 1'), 'Susanna 1') 67 | self.assertEqual(f('story of susanna 1'), 'Susanna 1') 68 | self.assertEqual(f('story of sus 1'), 'Susanna 1') 69 | 70 | def test_bel_and_the_dragon(self): 71 | self.assertEqual(f('bel and the dragon 1'), 72 | 'Bel and the Dragon 1') 73 | self.assertEqual(f('bel 1'), 74 | 'Bel and the Dragon 1') 75 | self.assertEqual(f('bel dragon 1'), 76 | 'Bel and the Dragon 1') 77 | 78 | def test_1_maccabees(self): 79 | self.assertEqual(f('1 maccabees 1:1'), 'I Maccabees 1:1') 80 | self.assertEqual(f('1Macc 1:1'), 'I Maccabees 1:1') 81 | self.assertEqual(f('I Macc 1:1'), 'I Maccabees 1:1') 82 | self.assertEqual(f('I Maccabees 1:1'), 'I Maccabees 1:1') 83 | 84 | def test_2_maccabees(self): 85 | self.assertEqual(f('2 maccabees 1:1'), 'II Maccabees 1:1') 86 | self.assertEqual(f('2Macc 1:1'), 'II Maccabees 1:1') 87 | self.assertEqual(f('II Macc 1:1'), 'II Maccabees 1:1') 88 | self.assertEqual(f('II Maccabees 1:1'), 'II Maccabees 1:1') 89 | 90 | -------------------------------------------------------------------------------- /scriptures/tests/test_normalization.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from .. import normalize_reference, scripture_re 4 | 5 | def normalize(txt): 6 | return normalize_reference(*scripture_re.match(txt).groups()) 7 | 8 | class TestNormalization(unittest.TestCase): 9 | def setUp(self): 10 | pass 11 | 12 | def test_single_reference(self): 13 | """ 14 | format: book c:v 15 | """ 16 | # multi-chapter book 17 | self.assertEqual(normalize('John 1:1'), ('John', 1, 1, 1, 1)) 18 | self.assertEqual(normalize('John 2:3'), ('John', 2, 3, 2, 3)) 19 | 20 | # single-chapter book 21 | self.assertEqual(normalize('Jude 1:3'), ('Jude', 1, 3, 1, 3)) 22 | 23 | def test_single_chapter_ref(self): 24 | """ 25 | format: book c 26 | 27 | This format is repeated in a different test for a single-chapter 28 | book, where it is interpreted as: book v 29 | 30 | """ 31 | # multi-chapter book 32 | self.assertEqual(normalize('John 1'), ('John', 1, 1, 1, 51)) 33 | self.assertEqual(normalize('John 2'), ('John', 2, 1, 2, 25)) 34 | 35 | # N/A for single-chapter book 36 | 37 | def test_multiverse_ref(self): 38 | """ 39 | format: book c:v-ev 40 | """ 41 | # multi-chapter book 42 | self.assertEqual(normalize('John 1:1-3'), ('John', 1, 1, 1, 3)) 43 | self.assertEqual(normalize('John 2:3-5'), ('John', 2, 3, 2, 5)) 44 | 45 | # single-chapter book 46 | self.assertEqual(normalize('Jude 1:3-5'), ('Jude', 1, 3, 1, 5)) 47 | 48 | def test_multichapter_multiverse_ref(self): 49 | """ 50 | format: book c:v-ec:ev 51 | """ 52 | # multi-chapter book 53 | self.assertEqual(normalize('John 2:2-2:7'), ('John', 2, 2, 2, 7)) 54 | self.assertEqual(normalize('John 2:3-4:5'), ('John', 2, 3, 4, 5)) 55 | 56 | # N/A for single-chapter book 57 | 58 | def test_multichapter_ref(self): 59 | """ 60 | format: book c-ec 61 | 62 | This format is repeated in a different test for a single-chapter 63 | book, where it is interpreted as: book v-ev 64 | """ 65 | # multi-chapter book 66 | self.assertEqual(normalize('John 1-5'), ('John', 1, 1, 5, 47)) 67 | self.assertEqual(normalize('John 2-6'), ('John', 2, 1, 6, 71)) 68 | 69 | # N/A for single-chapter book 70 | 71 | def test_singlechapter_book_verse_ref(self): 72 | """ 73 | format: book v 74 | 75 | This format is repeated in a different test for a multi-chapter 76 | book, where it is interpreted as: book c 77 | """ 78 | # N/A for multi-chapter book 79 | 80 | # single-chapter book 81 | self.assertEqual(normalize('Jude 5'), ('Jude', 1, 5, 1, 5)) 82 | 83 | 84 | def test_singlechapter_book_multiverse_ref(self): 85 | """ 86 | format: book v-ev 87 | 88 | This format is repeated in a different test for a multi-chapter 89 | book, where it is interpreted as: book c-ec 90 | """ 91 | # N/A for multi-chapter book 92 | 93 | # single-chapter book 94 | self.assertEqual(normalize('Jude 2-6'), ('Jude', 1, 2, 1, 6)) 95 | 96 | def test_implied_first_verse_ref_single_chapter(self): 97 | """ 98 | format: book ch-ech:ev 99 | """ 100 | # single-chapter book 101 | self.assertEqual(normalize('1 John 1-1:5'), ('I John', 1, 1, 1, 5)) 102 | 103 | # multi-chapter book 104 | self.assertEqual(normalize('I Sam 28-28:2'), ('I Samuel', 28, 1, 28, 2)) 105 | 106 | 107 | def test_implied_first_verse_ref_multi_chapter(self): 108 | """ 109 | format: book ch-ech:ev 110 | """ 111 | # single-chapter book 112 | self.assertEqual(normalize('Jude 1-1:5'), ('Jude', 1, 1, 1, 5)) 113 | 114 | # multi-chapter book 115 | self.assertEqual(normalize('I Sam 1-2:15'), ('I Samuel', 1, 1, 2, 15)) 116 | self.assertEqual(normalize('I Sam 2-3:5'), ('I Samuel', 2, 1, 3, 5)) 117 | 118 | 119 | -------------------------------------------------------------------------------- /scriptures/tests/test_protestant_booknames.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from .. import normalize_reference, scripture_re, reference_to_string 4 | 5 | def f(txt): 6 | """ 7 | accept a string containing a scripture reference, normalize it, and then 8 | return the reformatted string 9 | """ 10 | return reference_to_string( 11 | *normalize_reference(*scripture_re.match(txt).groups())) 12 | 13 | class TestBookNames(unittest.TestCase): 14 | def setUp(self): 15 | pass 16 | 17 | # Old Testament 18 | 19 | def test_genesis(self): 20 | self.assertEqual(f('genesis 1:1'), 'Genesis 1:1') 21 | self.assertEqual(f('gen 1:1'), 'Genesis 1:1') 22 | 23 | def test_exodus(self): 24 | self.assertEqual(f('exodus 1:1'), 'Exodus 1:1') 25 | self.assertEqual(f('exod 1:1'), 'Exodus 1:1') 26 | 27 | def test_leviticus(self): 28 | self.assertEqual(f('leviticus 1:1'), 'Leviticus 1:1') 29 | self.assertEqual(f('lev 1:1'), 'Leviticus 1:1') 30 | 31 | def test_numbers(self): 32 | self.assertEqual(f('numbers 1:1'), 'Numbers 1:1') 33 | self.assertEqual(f('num 1:1'), 'Numbers 1:1') 34 | 35 | def test_deuteronomy(self): 36 | self.assertEqual(f('deuteronomy 1:1'), 'Deuteronomy 1:1') 37 | self.assertEqual(f('deut 1:1'), 'Deuteronomy 1:1') 38 | 39 | def test_joshua(self): 40 | self.assertEqual(f('joshua 1:1'), 'Joshua 1:1') 41 | self.assertEqual(f('josh 1:1'), 'Joshua 1:1') 42 | 43 | def test_judges(self): 44 | self.assertEqual(f('judges 1:1'), 'Judges 1:1') 45 | self.assertEqual(f('judg 1:1'), 'Judges 1:1') 46 | 47 | def test_ruth(self): 48 | self.assertEqual(f('ruth 1:1'), 'Ruth 1:1') 49 | 50 | def test_i_samuel(self): 51 | self.assertEqual(f('I samuel 1:1'), 'I Samuel 1:1') 52 | self.assertEqual(f('1 samuel 1:1'), 'I Samuel 1:1') 53 | self.assertEqual(f('I sam 1:1'), 'I Samuel 1:1') 54 | self.assertEqual(f('1 sam 1:1'), 'I Samuel 1:1') 55 | self.assertEqual(f('1sam 1:1'), 'I Samuel 1:1') 56 | 57 | def test_ii_samuel(self): 58 | self.assertEqual(f('II samuel 1:1'), 'II Samuel 1:1') 59 | self.assertEqual(f('2 samuel 1:1'), 'II Samuel 1:1') 60 | self.assertEqual(f('II sam 1:1'), 'II Samuel 1:1') 61 | self.assertEqual(f('2 sam 1:1'), 'II Samuel 1:1') 62 | self.assertEqual(f('2sam 1:1'), 'II Samuel 1:1') 63 | 64 | def test_i_kings(self): 65 | self.assertEqual(f('I kings 1:1'), 'I Kings 1:1') 66 | self.assertEqual(f('1 kings 1:1'), 'I Kings 1:1') 67 | self.assertEqual(f('I kgs 1:1'), 'I Kings 1:1') 68 | self.assertEqual(f('1 kgs 1:1'), 'I Kings 1:1') 69 | self.assertEqual(f('1kgs 1:1'), 'I Kings 1:1') 70 | 71 | def test_ii_kings(self): 72 | self.assertEqual(f('II kings 1:1'), 'II Kings 1:1') 73 | self.assertEqual(f('2 kings 1:1'), 'II Kings 1:1') 74 | self.assertEqual(f('II kgs 1:1'), 'II Kings 1:1') 75 | self.assertEqual(f('2 kgs 1:1'), 'II Kings 1:1') 76 | self.assertEqual(f('2kgs 1:1'), 'II Kings 1:1') 77 | 78 | def test_i_chronicles(self): 79 | self.assertEqual(f('I chronicles 1:1'), 'I Chronicles 1:1') 80 | self.assertEqual(f('1 chronicles 1:1'), 'I Chronicles 1:1') 81 | 82 | self.assertEqual(f('I chr 1:1'), 'I Chronicles 1:1') 83 | self.assertEqual(f('I chro 1:1'), 'I Chronicles 1:1') 84 | self.assertEqual(f('I chron 1:1'), 'I Chronicles 1:1') 85 | 86 | self.assertEqual(f('1 chr 1:1'), 'I Chronicles 1:1') 87 | self.assertEqual(f('1 chro 1:1'), 'I Chronicles 1:1') 88 | self.assertEqual(f('1 chron 1:1'), 'I Chronicles 1:1') 89 | 90 | def test_ii_chronicles(self): 91 | self.assertEqual(f('II chronicles 1:1'), 'II Chronicles 1:1') 92 | self.assertEqual(f('2 chronicles 1:1'), 'II Chronicles 1:1') 93 | 94 | self.assertEqual(f('II chr 1:1'), 'II Chronicles 1:1') 95 | self.assertEqual(f('II chro 1:1'), 'II Chronicles 1:1') 96 | self.assertEqual(f('II chron 1:1'), 'II Chronicles 1:1') 97 | 98 | self.assertEqual(f('2 chr 1:1'), 'II Chronicles 1:1') 99 | self.assertEqual(f('2 chro 1:1'), 'II Chronicles 1:1') 100 | self.assertEqual(f('2 chron 1:1'), 'II Chronicles 1:1') 101 | 102 | 103 | def test_ezra(self): 104 | self.assertEqual(f('ezra 1:1'), 'Ezra 1:1') 105 | 106 | def test_nehemiah(self): 107 | self.assertEqual(f('nehemiah 1:1'), 'Nehemiah 1:1') 108 | self.assertEqual(f('neh 1:1'), 'Nehemiah 1:1') 109 | 110 | def test_esther(self): 111 | self.assertEqual(f('esther 1:1'), 'Esther 1:1') 112 | self.assertEqual(f('esth 1:1'), 'Esther 1:1') 113 | 114 | def test_job(self): 115 | self.assertEqual(f('job 1:1'), 'Job 1:1') 116 | 117 | def test_psalms(self): 118 | self.assertEqual(f('psalms 1:1'), 'Psalms 1:1') 119 | self.assertEqual(f('ps 1:1'), 'Psalms 1:1') 120 | self.assertEqual(f('psa 1:1'), 'Psalms 1:1') 121 | self.assertEqual(f('psalm 1:1'), 'Psalms 1:1') 122 | 123 | def test_proverbs(self): 124 | self.assertEqual(f('proverbs 1:1'), 'Proverbs 1:1') 125 | self.assertEqual(f('prov 1:1'), 'Proverbs 1:1') 126 | 127 | def test_ecclesiastes(self): 128 | self.assertEqual(f('ecclesiastes 1:1'), 'Ecclesiastes 1:1') 129 | self.assertEqual(f('ecc 1:1'), 'Ecclesiastes 1:1') 130 | self.assertEqual(f('eccl 1:1'), 'Ecclesiastes 1:1') 131 | self.assertEqual(f('eccles 1:1'), 'Ecclesiastes 1:1') 132 | 133 | def test_song_of_solomon(self): 134 | self.assertEqual(f('song of solomon 1:1'), 'Song of Solomon 1:1') 135 | self.assertEqual(f('song 1:1'), 'Song of Solomon 1:1') 136 | self.assertEqual(f('song of sol 1:1'), 'Song of Solomon 1:1') 137 | 138 | def test_isaiah(self): 139 | self.assertEqual(f('isaiah 1:1'), 'Isaiah 1:1') 140 | self.assertEqual(f('isa 1:1'), 'Isaiah 1:1') 141 | 142 | def test_jeremiah(self): 143 | self.assertEqual(f('jeremiah 1:1'), 'Jeremiah 1:1') 144 | self.assertEqual(f('jer 1:1'), 'Jeremiah 1:1') 145 | 146 | def test_lamentations(self): 147 | self.assertEqual(f('lamentations 1:1'), 'Lamentations 1:1') 148 | self.assertEqual(f('lam 1:1'), 'Lamentations 1:1') 149 | 150 | def test_ezekiel(self): 151 | self.assertEqual(f('ezekiel 1:1'), 'Ezekiel 1:1') 152 | self.assertEqual(f('ezek 1:1'), 'Ezekiel 1:1') 153 | 154 | def test_daniel(self): 155 | self.assertEqual(f('daniel 1:1'), 'Daniel 1:1') 156 | self.assertEqual(f('dan 1:1'), 'Daniel 1:1') 157 | 158 | def test_hosea(self): 159 | self.assertEqual(f('hosea 1:1'), 'Hosea 1:1') 160 | self.assertEqual(f('hos 1:1'), 'Hosea 1:1') 161 | 162 | def test_joel(self): 163 | self.assertEqual(f('joel 1:1'), 'Joel 1:1') 164 | 165 | def test_amos(self): 166 | self.assertEqual(f('amos 1:1'), 'Amos 1:1') 167 | 168 | def test_obadiah(self): 169 | self.assertEqual(f('obadiah 1:1'), 'Obadiah 1') 170 | self.assertEqual(f('obad 1:1'), 'Obadiah 1') 171 | 172 | def test_jonah(self): 173 | self.assertEqual(f('jonah 1:1'), 'Jonah 1:1') 174 | self.assertEqual(f('jon 1:1'), 'Jonah 1:1') 175 | 176 | def test_micah(self): 177 | self.assertEqual(f('micah 1:1'), 'Micah 1:1') 178 | self.assertEqual(f('mic 1:1'), 'Micah 1:1') 179 | 180 | def test_nahum(self): 181 | self.assertEqual(f('nahum 1:1'), 'Nahum 1:1') 182 | self.assertEqual(f('nah 1:1'), 'Nahum 1:1') 183 | 184 | def test_habakkuk(self): 185 | self.assertEqual(f('habakkuk 1:1'), 'Habakkuk 1:1') 186 | self.assertEqual(f('hab 1:1'), 'Habakkuk 1:1') 187 | 188 | def test_zephaniah(self): 189 | self.assertEqual(f('zephaniah 1:1'), 'Zephaniah 1:1') 190 | self.assertEqual(f('zeph 1:1'), 'Zephaniah 1:1') 191 | 192 | def test_haggai(self): 193 | self.assertEqual(f('haggai 1:1'), 'Haggai 1:1') 194 | self.assertEqual(f('hag 1:1'), 'Haggai 1:1') 195 | 196 | def test_zechariah(self): 197 | self.assertEqual(f('zechariah 1:1'), 'Zechariah 1:1') 198 | self.assertEqual(f('zech 1:1'), 'Zechariah 1:1') 199 | 200 | def test_malachi(self): 201 | self.assertEqual(f('malachi 1:1'), 'Malachi 1:1') 202 | self.assertEqual(f('mal 1:1'), 'Malachi 1:1') 203 | 204 | # /Old Testament 205 | 206 | # New Testament 207 | 208 | def test_matthew(self): 209 | self.assertEqual(f('matthew 1:1'), 'Matthew 1:1') 210 | self.assertEqual(f('matt 1:1'), 'Matthew 1:1') 211 | 212 | def test_mark(self): 213 | self.assertEqual(f('mark 1:1'), 'Mark 1:1') 214 | 215 | def test_luke(self): 216 | self.assertEqual(f('luke 1:1'), 'Luke 1:1') 217 | 218 | def test_john(self): 219 | self.assertEqual(f('john 1:1'), 'John 1:1') 220 | 221 | def test_acts(self): 222 | self.assertEqual(f('acts 1:1'), 'Acts 1:1') 223 | 224 | def test_romans(self): 225 | self.assertEqual(f('romans 1:1'), 'Romans 1:1') 226 | self.assertEqual(f('rom 1:1'), 'Romans 1:1') 227 | 228 | def test_i_corinthians(self): 229 | self.assertEqual(f('I corinthians 1:1'), 'I Corinthians 1:1') 230 | self.assertEqual(f('I cor 1:1'), 'I Corinthians 1:1') 231 | self.assertEqual(f('1 corinthians 1:1'), 'I Corinthians 1:1') 232 | self.assertEqual(f('1 cor 1:1'), 'I Corinthians 1:1') 233 | 234 | self.assertEqual(f('Icorinthians 1:1'), 'I Corinthians 1:1') 235 | self.assertEqual(f('Icor 1:1'), 'I Corinthians 1:1') 236 | self.assertEqual(f('1corinthians 1:1'), 'I Corinthians 1:1') 237 | self.assertEqual(f('1cor 1:1'), 'I Corinthians 1:1') 238 | 239 | def test_ii_corinthians(self): 240 | self.assertEqual(f('II corinthians 1:1'), 'II Corinthians 1:1') 241 | self.assertEqual(f('II cor 1:1'), 'II Corinthians 1:1') 242 | self.assertEqual(f('2 corinthians 1:1'), 'II Corinthians 1:1') 243 | self.assertEqual(f('2 cor 1:1'), 'II Corinthians 1:1') 244 | 245 | self.assertEqual(f('IIcorinthians 1:1'), 'II Corinthians 1:1') 246 | self.assertEqual(f('IIcor 1:1'), 'II Corinthians 1:1') 247 | self.assertEqual(f('2corinthians 1:1'), 'II Corinthians 1:1') 248 | self.assertEqual(f('2cor 1:1'), 'II Corinthians 1:1') 249 | 250 | def test_galatians(self): 251 | self.assertEqual(f('galatians 1:1'), 'Galatians 1:1') 252 | self.assertEqual(f('gal 1:1'), 'Galatians 1:1') 253 | 254 | def test_ephesians(self): 255 | self.assertEqual(f('ephesians 1:1'), 'Ephesians 1:1') 256 | self.assertEqual(f('eph 1:1'), 'Ephesians 1:1') 257 | 258 | def test_philippians(self): 259 | self.assertEqual(f('philippians 1:1'), 'Philippians 1:1') 260 | self.assertEqual(f('phil 1:1'), 'Philippians 1:1') 261 | 262 | def test_colossians(self): 263 | self.assertEqual(f('colossians 1:1'), 'Colossians 1:1') 264 | self.assertEqual(f('col 1:1'), 'Colossians 1:1') 265 | 266 | def test_i_thessalonians(self): 267 | self.assertEqual(f('I thessalonians 1:1'), 'I Thessalonians 1:1') 268 | self.assertEqual(f('I thess 1:1'), 'I Thessalonians 1:1') 269 | self.assertEqual(f('1 thessalonians 1:1'), 'I Thessalonians 1:1') 270 | self.assertEqual(f('1 thess 1:1'), 'I Thessalonians 1:1') 271 | 272 | self.assertEqual(f('Ithessalonians 1:1'), 'I Thessalonians 1:1') 273 | self.assertEqual(f('Ithess 1:1'), 'I Thessalonians 1:1') 274 | self.assertEqual(f('1thessalonians 1:1'), 'I Thessalonians 1:1') 275 | self.assertEqual(f('1thess 1:1'), 'I Thessalonians 1:1') 276 | 277 | def test_ii_thessalonians(self): 278 | self.assertEqual(f('II thessalonians 1:1'), 'II Thessalonians 1:1') 279 | self.assertEqual(f('II thess 1:1'), 'II Thessalonians 1:1') 280 | self.assertEqual(f('2 thessalonians 1:1'), 'II Thessalonians 1:1') 281 | self.assertEqual(f('2 thess 1:1'), 'II Thessalonians 1:1') 282 | 283 | self.assertEqual(f('IIthessalonians 1:1'), 'II Thessalonians 1:1') 284 | self.assertEqual(f('IIthess 1:1'), 'II Thessalonians 1:1') 285 | self.assertEqual(f('2thessalonians 1:1'), 'II Thessalonians 1:1') 286 | self.assertEqual(f('2thess 1:1'), 'II Thessalonians 1:1') 287 | 288 | 289 | def test_i_timothy(self): 290 | self.assertEqual(f('I timothy 1:1'), 'I Timothy 1:1') 291 | self.assertEqual(f('I tim 1:1'), 'I Timothy 1:1') 292 | self.assertEqual(f('1 timothy 1:1'), 'I Timothy 1:1') 293 | self.assertEqual(f('1 tim 1:1'), 'I Timothy 1:1') 294 | 295 | self.assertEqual(f('Itimothy 1:1'), 'I Timothy 1:1') 296 | self.assertEqual(f('Itim 1:1'), 'I Timothy 1:1') 297 | self.assertEqual(f('1timothy 1:1'), 'I Timothy 1:1') 298 | self.assertEqual(f('1tim 1:1'), 'I Timothy 1:1') 299 | 300 | def test_ii_timothy(self): 301 | self.assertEqual(f('II timothy 1:1'), 'II Timothy 1:1') 302 | self.assertEqual(f('II tim 1:1'), 'II Timothy 1:1') 303 | self.assertEqual(f('2 timothy 1:1'), 'II Timothy 1:1') 304 | self.assertEqual(f('2 tim 1:1'), 'II Timothy 1:1') 305 | 306 | self.assertEqual(f('IItimothy 1:1'), 'II Timothy 1:1') 307 | self.assertEqual(f('IItim 1:1'), 'II Timothy 1:1') 308 | self.assertEqual(f('2timothy 1:1'), 'II Timothy 1:1') 309 | self.assertEqual(f('2tim 1:1'), 'II Timothy 1:1') 310 | 311 | def test_titus(self): 312 | self.assertEqual(f('titus 1:1'), 'Titus 1:1') 313 | self.assertEqual(f('tit 1:1'), 'Titus 1:1') 314 | 315 | def test_philemon(self): 316 | self.assertEqual(f('philemon 1:1'), 'Philemon 1') 317 | self.assertEqual(f('phile 1:1'), 'Philemon 1') 318 | self.assertEqual(f('philem 1:1'), 'Philemon 1') 319 | self.assertEqual(f('phlm 1:1'), 'Philemon 1') 320 | 321 | def test_hebrews(self): 322 | self.assertEqual(f('hebrews 1:1'), 'Hebrews 1:1') 323 | self.assertEqual(f('heb 1:1'), 'Hebrews 1:1') 324 | 325 | def test_james(self): 326 | self.assertEqual(f('james 1:1'), 'James 1:1') 327 | self.assertEqual(f('jas 1:1'), 'James 1:1') 328 | 329 | def test_i_peter(self): 330 | self.assertEqual(f('I peter 1:1'), 'I Peter 1:1') 331 | self.assertEqual(f('I pet 1:1'), 'I Peter 1:1') 332 | self.assertEqual(f('1 peter 1:1'), 'I Peter 1:1') 333 | self.assertEqual(f('1 pet 1:1'), 'I Peter 1:1') 334 | 335 | self.assertEqual(f('Ipeter 1:1'), 'I Peter 1:1') 336 | self.assertEqual(f('Ipet 1:1'), 'I Peter 1:1') 337 | self.assertEqual(f('1peter 1:1'), 'I Peter 1:1') 338 | self.assertEqual(f('1pet 1:1'), 'I Peter 1:1') 339 | 340 | def test_i_peter(self): 341 | self.assertEqual(f('II peter 1:1'), 'II Peter 1:1') 342 | self.assertEqual(f('II pet 1:1'), 'II Peter 1:1') 343 | self.assertEqual(f('2 peter 1:1'), 'II Peter 1:1') 344 | self.assertEqual(f('2 pet 1:1'), 'II Peter 1:1') 345 | 346 | self.assertEqual(f('IIpeter 1:1'), 'II Peter 1:1') 347 | self.assertEqual(f('IIpet 1:1'), 'II Peter 1:1') 348 | self.assertEqual(f('2peter 1:1'), 'II Peter 1:1') 349 | self.assertEqual(f('2pet 1:1'), 'II Peter 1:1') 350 | 351 | 352 | def test_i_john(self): 353 | self.assertEqual(f('I john 1:1'), 'I John 1:1') 354 | self.assertEqual(f('1 john 1:1'), 'I John 1:1') 355 | 356 | self.assertEqual(f('Ijohn 1:1'), 'I John 1:1') 357 | self.assertEqual(f('1john 1:1'), 'I John 1:1') 358 | 359 | def test_ii_John(self): 360 | self.assertEqual(f('II john 1:1'), 'II John 1') 361 | self.assertEqual(f('2 john 1:1'), 'II John 1') 362 | 363 | self.assertEqual(f('IIjohn 1:1'), 'II John 1') 364 | self.assertEqual(f('2john 1:1'), 'II John 1') 365 | 366 | def test_iii_john(self): 367 | self.assertEqual(f('III john 1:1'), 'III John 1') 368 | self.assertEqual(f('3 john 1:1'), 'III John 1') 369 | 370 | self.assertEqual(f('IIIjohn 1:1'), 'III John 1') 371 | self.assertEqual(f('3john 1:1'), 'III John 1') 372 | 373 | def test_jude(self): 374 | self.assertEqual(f('jude 1:1'), 'Jude 1') 375 | 376 | def test_revelation(self): 377 | self.assertEqual(f('revelation 1:1'), 'Revelation of Jesus Christ 1:1') 378 | self.assertEqual(f('revelation of jesus christ 1:1'), 'Revelation of Jesus Christ 1:1') 379 | self.assertEqual(f('rev 1:1'), 'Revelation of Jesus Christ 1:1') 380 | 381 | # /New Testament 382 | 383 | -------------------------------------------------------------------------------- /scriptures/tests/test_reference_to_string.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from .. import normalize_reference, scripture_re, reference_to_string 4 | 5 | def f(txt): 6 | """ 7 | accept a string containing a scripture reference, normalize it, and then 8 | return the reformatted string 9 | """ 10 | return reference_to_string( 11 | *normalize_reference(*scripture_re.match(txt).groups())) 12 | 13 | class TestReferenceToSting(unittest.TestCase): 14 | def setUp(self): 15 | pass 16 | 17 | def test_single_reference(self): 18 | """ 19 | for multi-chapter books, output should be 20 | book c:v 21 | for single-chapter books, output should be 22 | book v 23 | 24 | """ 25 | # multi-chapter book 26 | self.assertEqual(f('John 1:1'), 'John 1:1') 27 | self.assertEqual(f('John 2:3'), 'John 2:3') 28 | 29 | # single-chapter book 30 | self.assertEqual(f('Jude 3'), 'Jude 3') 31 | self.assertEqual(f('Jude 1:3'), 'Jude 3') 32 | 33 | def test_single_chapter_ref(self): 34 | """ 35 | for multi-chapter books, output should be 36 | book c 37 | for single-chapter books, this does not make sense, as b x is 38 | interpreted as b v 39 | 40 | """ 41 | # multi-chapter book 42 | self.assertEqual(f('John 1:1-51'), 'John 1') 43 | self.assertEqual(f('John 1'), 'John 1') 44 | self.assertEqual(f('John 2:1-25'), 'John 2') 45 | self.assertEqual(f('John 2'), 'John 2') 46 | 47 | def test_multiverse_ref(self): 48 | """ 49 | for multi-chapter books, output should be 50 | book c:v-ev 51 | for single-chapter books, output should be 52 | book v-ev 53 | """ 54 | # multi-chapter book 55 | self.assertEqual(f('John 1:1-3'), 'John 1:1-3') 56 | self.assertEqual(f('John 2:3-5'), 'John 2:3-5') 57 | 58 | # single-chapter book 59 | self.assertEqual(f('Jude 1:3-5'), 'Jude 3-5') 60 | self.assertEqual(f('Jude 3-5'), 'Jude 3-5') 61 | 62 | def test_multichapter_multiverse_ref(self): 63 | """ 64 | for multi-chapter books, output should be 65 | b c:v-ec:ev 66 | for single-chapter books, input and output chapters are both one 67 | b v-ev 68 | """ 69 | # multi-chapter book 70 | self.assertEqual(f('John 2:3-4:5'), 'John 2:3-4:5') 71 | 72 | # single-chapter book 73 | self.assertEqual(f('Jude 1:3-1:5'), 'Jude 3-5') 74 | 75 | def test_multichapter_ref(self): 76 | """ 77 | for multi-chapter books, output should be: 78 | b c-ec 79 | for single-chapter books, this does not make sense, as b x-x is 80 | interpreted as b v-ev 81 | """ 82 | # multi-chapter book 83 | self.assertEqual(f('John 1-5'), 'John 1-5') 84 | self.assertEqual(f('John 2-6'), 'John 2-6') 85 | 86 | # N/A for single-chapter book 87 | 88 | def test_singlechapter_book_verse_ref(self): 89 | """ 90 | for multi-chapter books, this does not make sense as b x is interpreted 91 | as book c 92 | 93 | for single-chapter books, output should be: 94 | b v 95 | """ 96 | # N/A for multi-chapter book 97 | 98 | # single-chapter book 99 | self.assertEqual(f('Jude 5'), 'Jude 5') 100 | 101 | 102 | def test_singlechapter_book_multiverse_ref(self): 103 | """ 104 | for mult-chapter books, this does not make sense as b x-x is 105 | interpreted as b c-ec 106 | 107 | for single-chapter books, output should be: 108 | b v-ev 109 | """ 110 | # N/A for multi-chapter book 111 | 112 | # single-chapter book 113 | self.assertEqual(f('Jude 2-6'), 'Jude 2-6') 114 | 115 | def test_implied_first_verse_ref(self): 116 | """ 117 | for multi-chapter books, single chapter ref, output should be 118 | b c:v-ev 119 | for multi-chapter books, multi chapter ref, output should be 120 | b c:v-ec:ev 121 | for single-chapter books, input and output chapters are both one 122 | b v-ev 123 | """ 124 | 125 | # multi-chapter book 126 | self.assertEqual(f('John 2-2:4'), 'John 2:1-4') 127 | self.assertEqual(f('John 2-3:3'), 'John 2:1-3:3') 128 | 129 | # single-chapter book 130 | self.assertEqual(f('Jude 1-1:6'), 'Jude 1-6') 131 | -------------------------------------------------------------------------------- /scriptures/texts/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import InvalidReferenceException 2 | -------------------------------------------------------------------------------- /scriptures/texts/base.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | import re 3 | 4 | class InvalidReferenceException(Exception): 5 | """ 6 | Invalid Reference Exception 7 | """ 8 | pass 9 | 10 | class Text: 11 | def __init__(self): 12 | # Check for books 13 | if hasattr(self, 'books'): 14 | # make sure it is a dictionary 15 | if not isinstance(self.books, dict): 16 | raise Exception('"books" should be a dictionary, who\'s values are four valued tuples (Book Name, Abbreviation, Regex, [ch1_verse_count, ch2_verse_count, ...])') 17 | 18 | # set the regex instance variables 19 | self.book_re_string ='|'.join(b[2] for b in self.books.values()) 20 | self.book_re = re.compile(self.book_re_string, re.IGNORECASE | re.UNICODE) 21 | 22 | # set instance compiled scripture reference regex 23 | self.scripture_re = re.compile( 24 | r'\b(?P%s)\s*' \ 25 | '(?P\d{1,3})' \ 26 | '(?:\s*:\s*(?P\d{1,3}))?' \ 27 | '(?:\s*[-\u2013\u2014]\s*' \ 28 | '(?P\d{1,3}(?=\s*:\s*))?' \ 29 | '(?:\s*:\s*)?' \ 30 | '(?P\d{1,3})?' \ 31 | ')?' % (self.book_re_string,), re.IGNORECASE | re.UNICODE) 32 | 33 | else: 34 | raise Exception('Text has no "books"') 35 | 36 | def get_book(self, name): 37 | """ 38 | Get a book from its name or None if not found 39 | """ 40 | for book in self.books.values(): 41 | if re.match('^%s$' % book[2], name, re.IGNORECASE): 42 | return book 43 | 44 | return None 45 | 46 | def extract(self, text): 47 | """ 48 | Extract a list of tupled scripture references from a block of text 49 | """ 50 | references = [] 51 | for r in re.finditer(self.scripture_re, text): 52 | try: 53 | references.append(self.normalize_reference(*r.groups())) 54 | except InvalidReferenceException: 55 | pass 56 | return references 57 | 58 | def is_valid_reference(self, bookname, chapter, verse=None, 59 | end_chapter=None, end_verse=None): 60 | """ 61 | Check to see if a scripture reference is valid 62 | """ 63 | try: 64 | return self.normalize_reference(bookname, chapter, verse, 65 | end_chapter, end_verse) is not None 66 | except InvalidReferenceException: 67 | return False 68 | 69 | def reference_to_string(self, bookname, chapter, verse=None, 70 | end_chapter=None, end_verse=None): 71 | """ 72 | Get a display friendly string from a scripture reference 73 | """ 74 | book=None 75 | 76 | bn, c, v, ec, ev = self.normalize_reference(bookname, chapter, verse, 77 | end_chapter, end_verse) 78 | 79 | book = self.get_book(bn) 80 | 81 | if c == ec and len(book[3]) == 1: # single chapter book 82 | if v == ev: # single verse 83 | return '{0} {1}'.format(bn, v) 84 | else: # multiple verses 85 | return '{0} {1}-{2}'.format(bn, v, ev) 86 | else: # multichapter book 87 | if c == ec: # same start and end chapters 88 | if v == 1 and ev == book[3][c-1]: # full chapter 89 | return '{0} {1}'.format(bn, c) 90 | elif v == ev: # single verse 91 | return '{0} {1}:{2}'.format(bn, c, v) 92 | else: # multiple verses 93 | return '{0} {1}:{2}-{3}'.format( 94 | bn, c, v, ev) 95 | else: # multiple chapters 96 | if v == 1 and ev == book[3][ec-1]: # multichapter ref 97 | return '{0} {1}-{2}'.format(bn, c, ec) 98 | else: # multi-chapter, multi-verse ref 99 | return '{0} {1}:{2}-{3}:{4}'.format(bn, c, v, ec, ev) 100 | 101 | def normalize_reference(self, bookname, chapter, verse=None, 102 | end_chapter=None, end_verse=None): 103 | """ 104 | Get a complete five value tuple scripture reference with full book name 105 | from partial data 106 | """ 107 | book = self.get_book(bookname) 108 | 109 | # SPECIAL CASES FOR: BOOKS WITH ONE CHAPTER AND MULTI-CHAPTER REFERENCES 110 | 111 | # If the ref is in format: (Book, #, None, None, ?) 112 | # This is a special case and indicates a reference in the format: Book 2-3 113 | if chapter is not None and verse is None and end_chapter is None: 114 | # If there is only one chapter in this book, set the chapter to one and 115 | # treat the incoming chapter argument as though it were the verse. 116 | # This normalizes references such as: 117 | # Jude 2 and Jude 2-4 118 | if len(book[3]) == 1: 119 | verse=chapter 120 | chapter=1 121 | # If the ref is in format: (Book, ?, None, None, #) 122 | # This normalizes references such as: Revelation 2-3 123 | elif end_verse: 124 | verse=1 125 | end_chapter=end_verse 126 | end_verse=None 127 | # If the ref is in the format (Book, #, None, #, #) 128 | # this is a special case that indicates a reference in the format Book 3-4:5 129 | elif chapter is not None and verse is None and end_chapter is not None: 130 | # The solution is to set the verse to one, which is what is 131 | # most likely intended 132 | verse = 1 133 | 134 | 135 | # Convert to integers or leave as None 136 | chapter = int(chapter) if chapter else None 137 | verse = int(verse) if verse else None 138 | end_chapter = int(end_chapter) if end_chapter else chapter 139 | end_verse = int(end_verse) if end_verse else None 140 | if not book \ 141 | or (chapter is None or chapter < 1 or chapter > len(book[3])) \ 142 | or (verse is not None and (verse < 1 or verse > book[3][chapter-1])) \ 143 | or (end_chapter is not None and ( 144 | end_chapter < 1 145 | or end_chapter < chapter 146 | or end_chapter > len(book[3]))) \ 147 | or (end_verse is not None and( 148 | end_verse < 1 149 | or (end_chapter and end_verse > book[3][end_chapter-1]) 150 | or (chapter == end_chapter and end_verse < verse))): 151 | raise InvalidReferenceException() 152 | 153 | if not verse: 154 | return (book[0], chapter, 1, chapter, book[3][chapter-1]) 155 | if not end_verse: 156 | if end_chapter and end_chapter != chapter: 157 | end_verse = book[3][end_chapter-1] 158 | else: 159 | end_verse = verse 160 | if not end_chapter: 161 | end_chapter = chapter 162 | return (book[0], chapter, verse, end_chapter, end_verse) 163 | 164 | 165 | -------------------------------------------------------------------------------- /scriptures/texts/deuterocanon.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from .base import Text 3 | 4 | 5 | class Deuterocanon(Text): 6 | """ 7 | Deuterocanonical Books 8 | """ 9 | books = { 10 | 'tob': ('Tobit', 'Tob', 'Tob(?:it)?', 11 | [22, 14, 17, 21, 22, 17, 18, 21, 6, 12, 19, 22, 18, 15]), 12 | 13 | 'jdt': ('Judith', 'Jdt', 'Jud(?:ith)?', 14 | [ 15 | 16, 28, 10, 15, 24, 21, 32, 35, 14, 16 | 23, 23, 20, 20, 19, 13, 25 17 | ]), 18 | 19 | 'addesth': ('Additions to Esther', 'AddEsth', 20 | '(?:AddEsth|(?:Additions to|Rest of) Esther|Esther \\(Greek\\))', 21 | [ 22 | 39, 23, 22, 47, 28, 14, 10, 41, 32, 13 23 | ]), 24 | 25 | 'wis': ('The Wisdom of Solomon', 'Wis', 26 | '(?:The )?Wis(?:dom(?: of Solomon)?)?', 27 | [ 28 | 16, 24, 19, 20, 23, 25, 30, 20, 18, 29 | 21, 26, 27, 19, 31, 19, 29, 21, 30 | 25, 22 31 | ]), 32 | 33 | 'sir': ('Sirach', 'Sir', 34 | 'Sir(?:ach)?|Ecclesiasticus', 35 | [ 36 | 30, 18, 31, 31, 15, 37, 36, 19, 18, 37 | 31, 34, 18, 26, 27, 20, 30, 32, 33, 38 | 30, 31, 28, 27, 34, 26, 29, 30, 39 | 26, 28, 25, 31, 24, 31, 26, 20, 40 | 26, 31, 34, 35, 30, 23, 25, 33, 41 | 23, 26, 20, 25, 25, 16, 29, 30 42 | ]), 43 | 44 | 'bar': ('Baruch', 'Bar', 'Bar(?:uch)?', 45 | [ 46 | 21, 35, 37, 37, 9 47 | ]), 48 | 49 | 'epjer': ('Letter of Jeremiah', 'EpJer', 50 | 'EpJer|Letter of Jeremiah', 51 | [73]), 52 | 53 | 'prazar': ('Prayer of Azariah', 'prazar', 54 | '(?:prayer of |Pr)?Azar(?:iah)?|Song of (?:the )?Three Children', 55 | [68]), 56 | 57 | 'sus': ('Susanna', 'susanna', 58 | '(?:Story of )?sus(?:anna)?', 59 | [64]), 60 | 61 | 'bel': ('Bel and the Dragon', 'bel', 62 | 'bel(?:(?: and the)? dragon)?', 63 | [42]), 64 | 65 | '1macc': ('I Maccabees', '1Macc', '(?:1|I) ?Macc(?:abees)?', 66 | [ 67 | 64, 70, 60, 61, 68, 63, 50, 32, 73, 68 | 89, 74, 53, 53, 49, 41, 24 69 | ]), 70 | 71 | '2macc': ('II Maccabees', '2Macc', '(?:2|II) ?Macc(?:abees)?', 72 | [ 73 | 36, 32, 40, 50, 27, 31, 42, 36, 29, 74 | 38, 38, 45, 26, 46, 39 75 | ]), 76 | } 77 | -------------------------------------------------------------------------------- /scriptures/texts/kjv1611.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from .base import Text 3 | from .protestant import ProtestantCanon 4 | from .deuterocanon import Deuterocanon 5 | 6 | 7 | class KingJames1611(Text): 8 | """ 9 | KingJames1611 - Contains what is considered the protestant canonical texts, 10 | plus the Deuteronomical books (in its Apocrypha) 11 | plus its additional Apocryphal books (I and II Esdras) 12 | """ 13 | books = {} 14 | books.update(ProtestantCanon.books) 15 | books.update(Deuterocanon.books) 16 | books.update({ 17 | '1esd': ('I Esdras', '1Esd', '(?:(?:1|I)(?:\s)?)Esd(?:ras)?', 18 | [58, 30, 24, 63, 73, 34, 15, 96, 55]), 19 | '2esd': ('II Esdras', '2Esd', '(?:(?:2|II)(?:\s)?)Esd(?:ras)?', 20 | [40, 48, 36, 52, 56, 59, 70, 63, 21 | 47, 59, 46, 51, 58, 48, 63, 78]), 22 | 'prman': ('Prayer of Manasseh', 'prman', 23 | 'prman|(?:prayer of )?manasseh', 24 | [15]), 25 | }) 26 | 27 | -------------------------------------------------------------------------------- /scriptures/texts/protestant.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from .base import Text 3 | 4 | class ProtestantCanon(Text): 5 | """ 6 | Protestant Canonical Bible with Old and New Testaments 7 | """ 8 | books = { 9 | 'gen': ('Genesis', 'Gen', 'Gen(?:esis)?', [31, 25, 24, 26, 32, 22, 24, 22, 29, 32, 32, 20, 18, 24, 21, 16, 27, 33, 38, 18, 34, 24, 20, 67, 34, 35, 46, 22, 35, 43, 55, 32, 20, 31, 29, 43, 36, 30, 23, 23, 57, 38, 34, 34, 28, 34, 31, 22, 33, 26]), 10 | 'exod': ('Exodus', 'Exod', 'Exod(?:us)?', [22, 25, 22, 31, 23, 30, 25, 32, 35, 29, 10, 51, 22, 31, 27, 36, 16, 27, 25, 26, 36, 31, 33, 18, 40, 37, 21, 43, 46, 38, 18, 35, 23, 35, 35, 38, 29, 31, 43, 38]), 11 | 'lev': ('Leviticus', 'Lev', 'Lev(?:iticus)?', [17, 16, 17, 35, 19, 30, 38, 36, 24, 20, 47, 8, 59, 57, 33, 34, 16, 30, 37, 27, 24, 33, 44, 23, 55, 46, 34]), 12 | 'num': ('Numbers', 'Num', 'Num(?:bers)?', [54, 34, 51, 49, 31, 27, 89, 26, 23, 36, 35, 16, 33, 45, 41, 50, 13, 32, 22, 29, 35, 41, 30, 25, 18, 65, 23, 31, 40, 16, 54, 42, 56, 29, 34, 13]), 13 | 'deut': ('Deuteronomy', 'Deut', 'Deut(?:eronomy)?', [46, 37, 29, 49, 33, 25, 26, 20, 29, 22, 32, 32, 18, 29, 23, 22, 20, 22, 21, 20, 23, 30, 25, 22, 19, 19, 26, 68, 29, 20, 30, 52, 29, 12]), 14 | 'josh': ('Joshua', 'Josh', 'Josh(?:ua)?', [18, 24, 17, 24, 15, 27, 26, 35, 27, 43, 23, 24, 33, 15, 63, 10, 18, 28, 51, 9, 45, 34, 16, 33]), 15 | 'judg': ('Judges', 'Judg', 'Judg(?:es)?', [36, 23, 31, 24, 31, 40, 25, 35, 57, 18, 40, 15, 25, 20, 20, 31, 13, 31, 30, 48, 25]), 16 | 'ruth': ('Ruth', 'Ruth', 'Ruth', [22, 23, 18, 22]), 17 | '1sam': ('I Samuel', '1Sam', '(?:1|I)(?:\s)?Sam(?:uel)?', [28, 36, 21, 22, 12, 21, 17, 22, 27, 27, 15, 25, 23, 52, 35, 23, 58, 30, 24, 42, 15, 23, 29, 22, 44, 25, 12, 25, 11, 31, 13]), 18 | '2sam': ('II Samuel', '2Sam', '(?:2|II)(?:\s)?Sam(?:uel)?', [27, 32, 39, 12, 25, 23, 29, 18, 13, 19, 27, 31, 39, 33, 37, 23, 29, 33, 43, 26, 22, 51, 39, 25]), 19 | '1kgs': ('I Kings', '1Kgs', '(?:1|I)(?:\s)?K(?:in)?gs', [53, 46, 28, 34, 18, 38, 51, 66, 28, 29, 43, 33, 34, 31, 34, 34, 24, 46, 21, 43, 29, 53]), 20 | '2kgs': ('II Kings', '2Kgs', '(?:2|II)(?:\s)?K(?:in)?gs', [18, 25, 27, 44, 27, 33, 20, 29, 37, 36, 21, 21, 25, 29, 38, 20, 41, 37, 37, 21, 26, 20, 37, 20, 30]), 21 | '1chr': ('I Chronicles', '1Chr', '(?:1|I)(?:\s)?Chr(?:o(?:n(?:icles)?)?)?', [54, 55, 24, 43, 26, 81, 40, 40, 44, 14, 47, 40, 14, 17, 29, 43, 27, 17, 19, 8, 30, 19, 32, 31, 31, 32, 34, 21, 30]), 22 | '2chr': ('II Chronicles', '2Chr', '(?:2|II)(?:\s)?Chr(?:o(?:n(?:icles)?)?)?', [17, 18, 17, 22, 14, 42, 22, 18, 31, 19, 23, 16, 22, 15, 19, 14, 19, 34, 11, 37, 20, 12, 21, 27, 28, 23, 9, 27, 36, 27, 21, 33, 25, 33, 27, 23]), 23 | 'ezra': ('Ezra', 'Ezra', 'Ezra', [11, 70, 13, 24, 17, 22, 28, 36, 15, 44]), 24 | 'neh': ('Nehemiah', 'Neh', 'Neh(?:emiah)?', [11, 20, 32, 23, 19, 19, 73, 18, 38, 39, 36, 47, 31]), 25 | 'esth': ('Esther', 'Esth', 'Esth(?:er)?', [22, 23, 15, 17, 14, 14, 10, 17, 32, 3]), 26 | 'job': ('Job', 'Job', 'Job', [22, 13, 26, 21, 27, 30, 21, 22, 35, 22, 20, 25, 28, 22, 35, 22, 16, 21, 29, 29, 34, 30, 17, 25, 6, 14, 23, 28, 25, 31, 40, 22, 33, 37, 16, 33, 24, 41, 30, 24, 34, 17]), 27 | 'ps': ('Psalms', 'Ps', 'Ps(?:a)?(?:lm(?:s)?)?', [6, 12, 8, 8, 12, 10, 17, 9, 20, 18, 7, 8, 6, 7, 5, 11, 15, 50, 14, 9, 13, 31, 6, 10, 22, 12, 14, 9, 11, 12, 24, 11, 22, 22, 28, 12, 40, 22, 13, 17, 13, 11, 5, 26, 17, 11, 9, 14, 20, 23, 19, 9, 6, 7, 23, 13, 11, 11, 17, 12, 8, 12, 11, 10, 13, 20, 7, 35, 36, 5, 24, 20, 28, 23, 10, 12, 20, 72, 13, 19, 16, 8, 18, 12, 13, 17, 7, 18, 52, 17, 16, 15, 5, 23, 11, 13, 12, 9, 9, 5, 8, 28, 22, 35, 45, 48, 43, 13, 31, 7, 10, 10, 9, 8, 18, 19, 2, 29, 176, 7, 8, 9, 4, 8, 5, 6, 5, 6, 8, 8, 3, 18, 3, 3, 21, 26, 9, 8, 24, 13, 10, 7, 12, 15, 21, 10, 20, 14, 9, 6]), 28 | 'prov': ('Proverbs', 'Prov', 'Prov(?:erbs)?', [33, 22, 35, 27, 23, 35, 27, 36, 18, 32, 31, 28, 25, 35, 33, 33, 28, 24, 29, 30, 31, 29, 35, 34, 28, 28, 27, 28, 27, 33, 31]), 29 | 'eccl': ('Ecclesiastes', 'Eccl', 'Ecc(?:l(?:es(?:iastes)?)?)?', [18, 26, 22, 16, 20, 12, 29, 17, 18, 20, 10, 14]), 30 | 'song': ('Song of Solomon', 'Song', 'Song(?: of Sol(?:omon)?)?', [17, 17, 11, 16, 16, 13, 13, 14]), 31 | 'isa': ('Isaiah', 'Isa', 'Isa(?:iah)?', [31, 22, 26, 6, 30, 13, 25, 22, 21, 34, 16, 6, 22, 32, 9, 14, 14, 7, 25, 6, 17, 25, 18, 23, 12, 21, 13, 29, 24, 33, 9, 20, 24, 17, 10, 22, 38, 22, 8, 31, 29, 25, 28, 28, 25, 13, 15, 22, 26, 11, 23, 15, 12, 17, 13, 12, 21, 14, 21, 22, 11, 12, 19, 12, 25, 24]), 32 | 'jer': ('Jeremiah', 'Jer', 'Jer(?:emiah)?', [19, 37, 25, 31, 31, 30, 34, 22, 26, 25, 23, 17, 27, 22, 21, 21, 27, 23, 15, 18, 14, 30, 40, 10, 38, 24, 22, 17, 32, 24, 40, 44, 26, 22, 19, 32, 21, 28, 18, 16, 18, 22, 13, 30, 5, 28, 7, 47, 39, 46, 64, 34]), 33 | 'lam': ('Lamentations', 'Lam', 'Lam(?:entations)?', [22, 22, 66, 22, 22]), 34 | 'ezek': ('Ezekiel', 'Ezek', 'Ezek(?:iel)?', [28, 10, 27, 17, 17, 14, 27, 18, 11, 22, 25, 28, 23, 23, 8, 63, 24, 32, 14, 49, 32, 31, 49, 27, 17, 21, 36, 26, 21, 26, 18, 32, 33, 31, 15, 38, 28, 23, 29, 49, 26, 20, 27, 31, 25, 24, 23, 35]), 35 | 'dan': ('Daniel', 'Dan', 'Dan(?:iel)?', [21, 49, 30, 37, 31, 28, 28, 27, 27, 21, 45, 13]), 36 | 'hos': ('Hosea', 'Hos', 'Hos(?:ea)?', [11, 23, 5, 19, 15, 11, 16, 14, 17, 15, 12, 14, 16, 9]), 37 | 'joel': ('Joel', 'Joel', 'Joel', [20, 32, 21]), 38 | 'amos': ('Amos', 'Amos', 'Amos', [15, 16, 15, 13, 27, 14, 17, 14, 15]), 39 | 'obad': ('Obadiah', 'Obad', 'Obad(?:iah)?', [21]), 40 | 'jonah': ('Jonah', 'Jonah', 'Jon(?:ah)?', [17, 10, 10, 11]), 41 | 'mic': ('Micah', 'Mic', 'Mic(?:ah)?', [16, 13, 12, 13, 15, 16, 20]), 42 | 'nah': ('Nahum', 'Nah', 'Nah(?:um)?', [15, 13, 19]), 43 | 'hab': ('Habakkuk', 'Hab', 'Hab(?:akkuk)?', [17, 20, 19]), 44 | 'zeph': ('Zephaniah', 'Zeph', 'Zeph(?:aniah)?', [18, 15, 20]), 45 | 'hag': ('Haggai', 'Hag', 'Hag(?:gai)?', [15, 23]), 46 | 'zech': ('Zechariah', 'Zech', 'Zech(?:ariah)?', [21, 13, 10, 14, 11, 15, 14, 23, 17, 12, 17, 14, 9, 21]), 47 | 'mal': ('Malachi', 'Mal', 'Mal(?:achi)?', [14, 17, 18, 6]), 48 | 'matt': ('Matthew', 'Matt', 'Matt(?:hew)?', [25, 23, 17, 25, 48, 34, 29, 34, 38, 42, 30, 50, 58, 36, 39, 28, 27, 35, 30, 34, 46, 46, 39, 51, 46, 75, 66, 20]), 49 | 'mark': ('Mark', 'Mark', 'Mark', [45, 28, 35, 41, 43, 56, 37, 38, 50, 52, 33, 44, 37, 72, 47, 20]), 50 | 'luke': ('Luke', 'Luke', 'Luke', [80, 52, 38, 44, 39, 49, 50, 56, 62, 42, 54, 59, 35, 35, 32, 31, 37, 43, 48, 47, 38, 71, 56, 53]), 51 | 'john': ('John', 'John', '(?