Repository: joke2k/faker (python)

Issue:
Support for 9 digit SBN
* Faker version: 17.0.0
* OS: Windows 10

Brief summary of the issue goes here.

Before the formation of the ISBN there was a non-international Standard Book Number (SBN) used for a few years. While no longer used today, it might be nice to include SBNs as they are still on many books from the time. I'd be happy to work on a PR for this.

Pull request description:
Add SBN provider
### What does this change

Adds an SBN provider that generates (pre-International) Standard Book Numbers.

### What was wrong

See #1803 

### How this fixes it

Takes the current ISBN provider implementation and modifies it to match the older SBN model. This includes removing the usage of EAN and registration group in number generation, as well as editing the `_check_digit` method to work for SBN.

Fixes #1803 

Patch:
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index b0203685..71721f80 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 17.3.0
+current_version = 17.4.0
 files = VERSION faker/__init__.py docs/conf.py
 commit = True
 tag = True
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c604269b..1acaa82f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 ## Changelog
 
+### [v17.4.0 - 2023-02-28](https://github.com/joke2k/faker/compare/v17.3.0...v17.4.0)
+
+* Use the official name for North Macedonia due to the name change in 2019. Thanks @takis.
+
 ### [v17.3.0 - 2023-02-24](https://github.com/joke2k/faker/compare/v17.2.0...v17.3.0)
 
 * Add `zh_TW` `date_time` provider. Thanks @ew2664.
diff --git a/VERSION b/VERSION
index 5aadcd3f..e64ad13c 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-17.3.0
+17.4.0
diff --git a/docs/conf.py b/docs/conf.py
index f2f7ae2b..3a1cbebb 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -51,9 +51,9 @@ copyright = "2014, Daniele Faraglia"
 # built documents.
 #
 # The short X.Y version.
-version = "17.3.0"
+version = "17.4.0"
 # The full version, including alpha/beta/rc tags.
-release = "17.3.0"
+release = "17.4.0"
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/faker/__init__.py b/faker/__init__.py
index defd849c..f48d33fa 100644
--- a/faker/__init__.py
+++ b/faker/__init__.py
@@ -2,6 +2,6 @@ from faker.factory import Factory
 from faker.generator import Generator
 from faker.proxy import Faker
 
-VERSION = "17.3.0"
+VERSION = "17.4.0"
 
 __all__ = ("Factory", "Generator", "Faker")
diff --git a/faker/providers/address/bn_BD/__init__.py b/faker/providers/address/bn_BD/__init__.py
index 4f47ce98..0aa51915 100644
--- a/faker/providers/address/bn_BD/__init__.py
+++ b/faker/providers/address/bn_BD/__init__.py
@@ -321,7 +321,7 @@ class Provider(AddressProvider):
         "লিথুয়ানিয়া",
         "লাক্সেমবার্গ",
         "ম্যাকাও",
-        "মেসিডোনিয়া প্রজাতন্ত্র",
+        "উত্তর মেসিডোনিয়া প্রজাতন্ত্র",
         "মাদাগাস্কার",
         "মালাউই",
         "মালয়েশিয়া",
diff --git a/faker/providers/address/cs_CZ/__init__.py b/faker/providers/address/cs_CZ/__init__.py
index b902bb81..9054e301 100644
--- a/faker/providers/address/cs_CZ/__init__.py
+++ b/faker/providers/address/cs_CZ/__init__.py
@@ -1033,7 +1033,6 @@ class Provider(AddressProvider):
         "Lotyšsko",
         "Lucembursko",
         "Madagaskar",
-        "Makedonie",
         "Malajsie",
         "Malawi",
         "Maledivy",
@@ -1083,6 +1082,7 @@ class Provider(AddressProvider):
         "Saúdská Arábie",
         "Senegal",
         "Severní Korea",
+        "Severní Makedonie",
         "Seychely",
         "Sierra Leone",
         "Singapur",
diff --git a/faker/providers/address/da_DK/__init__.py b/faker/providers/address/da_DK/__init__.py
index bc0cabb2..1aae0298 100644
--- a/faker/providers/address/da_DK/__init__.py
+++ b/faker/providers/address/da_DK/__init__.py
@@ -2392,7 +2392,6 @@ class Provider(AddressProvider):
         "Litauen",
         "Luxembourg",
         "Madagaskar",
-        "Makedonien",
         "Malawi",
         "Malaysia",
         "Maldiverne",
@@ -2420,6 +2419,7 @@ class Provider(AddressProvider):
         "Nigeria",
         "Niue",
         "Nordkorea",
+        "Nordmakedonien",
         "Norge",
         "Oman",
         "Pakistan",
diff --git a/faker/providers/address/de/__init__.py b/faker/providers/address/de/__init__.py
index b8d9734e..d9f07fe8 100644
--- a/faker/providers/address/de/__init__.py
+++ b/faker/providers/address/de/__init__.py
@@ -134,7 +134,6 @@ class Provider(AddressProvider):
         "Mauretanien",
         "Mauritius",
         "Mayotte",
-        "Mazedonien",
         "Mexiko",
         "Mikronesien",
         "Monaco",
@@ -154,6 +153,7 @@ class Provider(AddressProvider):
         "Niger",
         "Nigeria",
         "Niue",
+        "Nordmazedonien",
         "Norfolkinsel",
         "Norwegen",
         "Nördliche Marianen",
diff --git a/faker/providers/address/el_GR/__init__.py b/faker/providers/address/el_GR/__init__.py
index 110f26c0..d7874279 100644
--- a/faker/providers/address/el_GR/__init__.py
+++ b/faker/providers/address/el_GR/__init__.py
@@ -249,6 +249,7 @@ class Provider(AddressProvider):
         "Γρενάδα",
         "Γροιλανδία",
         "Δανία",
+        "Δημοκρατία της Βόρειας Μακεδονίας",
         "Δημοκρατία της Κορέας",
         "Δομινίκα",
         "Δομινικανή Δημοκρατία",
@@ -374,7 +375,6 @@ class Provider(AddressProvider):
         "Ουζμπεκιστάν",
         "Ουκρανία",
         "Ουρουγουάη",
-        "Π.Γ.Δ. Μακεδονίας",
         "Πακιστάν",
         "Παλάου",
         "Παλαιστίνη",
diff --git a/faker/providers/address/en/__init__.py b/faker/providers/address/en/__init__.py
index 86755662..7d2124d7 100644
--- a/faker/providers/address/en/__init__.py
+++ b/faker/providers/address/en/__init__.py
@@ -132,7 +132,6 @@ class Provider(AddressProvider):
         "Lithuania",
         "Luxembourg",
         "Macao",
-        "Macedonia",
         "Madagascar",
         "Malawi",
         "Malaysia",
@@ -166,6 +165,7 @@ class Provider(AddressProvider):
         "Nigeria",
         "Niue",
         "Norfolk Island",
+        "North Macedonia",
         "Northern Mariana Islands",
         "Norway",
         "Oman",
diff --git a/faker/providers/address/es/__init__.py b/faker/providers/address/es/__init__.py
index 8588bc6c..726975c8 100644
--- a/faker/providers/address/es/__init__.py
+++ b/faker/providers/address/es/__init__.py
@@ -63,7 +63,6 @@ class Provider(AddressProvider):
         "Estados Unidos de América",
         "Estonia",
         "Etiopía",
-        "ex República Yugoslava de Macedonia",
         "Federación de Rusia",
         "Fiji",
         "Filipinas",
@@ -148,6 +147,7 @@ class Provider(AddressProvider):
         "República Centroafricana",
         "República Checa",
         "República de Corea",
+        "República de Macedonia del Norte",
         "República de Moldova",
         "República Democrática del Congo",
         "República Democrática Popular Lao",
diff --git a/faker/providers/address/fa_IR/__init__.py b/faker/providers/address/fa_IR/__init__.py
index ad79a701..c21889d3 100644
--- a/faker/providers/address/fa_IR/__init__.py
+++ b/faker/providers/address/fa_IR/__init__.py
@@ -243,7 +243,7 @@ class Provider(AddressProvider):
         "مراکش",
         "مصر",
         "مغولستان",
-        "مقدونیه",
+        "مقدونیه شمالی",
         "مکزیک",
         "موریتانی",
         "موریس",
diff --git a/faker/providers/address/fi_FI/__init__.py b/faker/providers/address/fi_FI/__init__.py
index d2aa50d4..4b05d39d 100644
--- a/faker/providers/address/fi_FI/__init__.py
+++ b/faker/providers/address/fi_FI/__init__.py
@@ -433,7 +433,6 @@ class Provider(AddressProvider):
         "Liettua",
         "Luxemburg",
         "Madagaskar",
-        "Makedonia",
         "Malawi",
         "Malediivit",
         "Malesia",
@@ -466,6 +465,7 @@ class Provider(AddressProvider):
         "Papua-Uusi-Guinea",
         "Paraguay",
         "Peru",
+        "Pohjois-Makedonia",
         "Korean demokraattinen kansantasavalta",
         "Portugali",
         "Puola",
diff --git a/faker/providers/address/fr_CH/__init__.py b/faker/providers/address/fr_CH/__init__.py
index c2f5bd33..88996048 100644
--- a/faker/providers/address/fr_CH/__init__.py
+++ b/faker/providers/address/fr_CH/__init__.py
@@ -214,7 +214,7 @@ class Provider(AddressProvider):
         "Lithuanie",
         "Luxembourg",
         "Macau",
-        "Macédoine",
+        "Macédoine du Nord",
         "Madagascar",
         "Malaisie",
         "Malawi",
diff --git a/faker/providers/address/fr_FR/__init__.py b/faker/providers/address/fr_FR/__init__.py
index 5aaff526..fa7010da 100644
--- a/faker/providers/address/fr_FR/__init__.py
+++ b/faker/providers/address/fr_FR/__init__.py
@@ -170,7 +170,7 @@ class Provider(AddressProvider):
         "Lithuanie",
         "Luxembourg",
         "Macau",
-        "Macédoine",
+        "Macédoine du Nord",
         "Madagascar",
         "Malaisie",
         "Malawi",
diff --git a/faker/providers/address/hr_HR/__init__.py b/faker/providers/address/hr_HR/__init__.py
index bd01a167..b3ae4ba3 100755
--- a/faker/providers/address/hr_HR/__init__.py
+++ b/faker/providers/address/hr_HR/__init__.py
@@ -461,7 +461,6 @@ class Provider(AddressProvider):
         "Mađarska",
         "Majote",
         "Makao",
-        "Makedonija",
         "Malavi",
         "Maldivi Maldives",
         "Malezija",
@@ -525,6 +524,7 @@ class Provider(AddressProvider):
         "Sint Maarten",
         "Sirija",
         "Sjedinjene Američke Države",
+        "Sjeverna Makedonija",
         "Sjeverni Marijanski Otoci",
         "Slovačka",
         "Slovenija",
diff --git a/faker/providers/address/hu_HU/__init__.py b/faker/providers/address/hu_HU/__init__.py
index 4fd17988..990f6379 100644
--- a/faker/providers/address/hu_HU/__init__.py
+++ b/faker/providers/address/hu_HU/__init__.py
@@ -257,6 +257,7 @@ class Provider(AddressProvider):
         "Eritrea",
         "Északi Mariana-szigetek",
         "Észak-Korea",
+        "Észak-Macedónia",
         "Észtország",
         "Etiópia",
         "Falkland-szigetek",
@@ -327,7 +328,6 @@ class Provider(AddressProvider):
         "Liechtenstein",
         "Litvánia",
         "Luxemburg",
-        "Macedónia",
         "Madagaszkár",
         "Magyarország",
         "Makaó",
diff --git a/faker/providers/address/hy_AM/__init__.py b/faker/providers/address/hy_AM/__init__.py
index 6b83e416..3f4c9510 100644
--- a/faker/providers/address/hy_AM/__init__.py
+++ b/faker/providers/address/hy_AM/__init__.py
@@ -204,7 +204,7 @@ class Provider(AddressProvider):
         "Լիտվա",
         "Լյուքսեմբուրգ",
         "Մակաո",
-        "Մակեդոնիա",
+        "Հյուսիսային Մակեդոնիա",
         "Մադագասկար",
         "Մալավի",
         "Մալազիա",
diff --git a/faker/providers/address/id_ID/__init__.py b/faker/providers/address/id_ID/__init__.py
index c3eeb727..35781ad3 100644
--- a/faker/providers/address/id_ID/__init__.py
+++ b/faker/providers/address/id_ID/__init__.py
@@ -405,6 +405,7 @@ class Provider(AddressProvider):
         "Lituania",
         "Luksemburg",
         "Madagaskar",
+        "Makedonia Utara",
         "Maladewa",
         "Malawi",
         "Malaysia",
@@ -444,7 +445,6 @@ class Provider(AddressProvider):
         "Republik Dominika",
         "Republik Irlandia",
         "Republik Kongo",
-        "Republik Makedonia",
         "Republik Rakyat Tiongkok",
         "Rumania",
         "Rusia",
diff --git a/faker/providers/address/it_IT/__init__.py b/faker/providers/address/it_IT/__init__.py
index 0ea6d455..6ba2a908 100644
--- a/faker/providers/address/it_IT/__init__.py
+++ b/faker/providers/address/it_IT/__init__.py
@@ -17489,7 +17489,7 @@ class Provider(AddressProvider):
         "Lituania",
         "Lussemburgo",
         "Macao",
-        "Macedonia",
+        "Macedonia del Nord",
         "Madagascar",
         "Malawi",
         "Malesia",
diff --git a/faker/providers/address/ja_JP/__init__.py b/faker/providers/address/ja_JP/__init__.py
index efad2387..4811eb90 100644
--- a/faker/providers/address/ja_JP/__init__.py
+++ b/faker/providers/address/ja_JP/__init__.py
@@ -139,7 +139,7 @@ class Provider(AddressProvider):
         "リトアニア",
         "ルクセンブルク",
         "マカオ",
-        "マケドニア共和国",
+        "北マケドニア共和国",
         "マダガスカル",
         "マラウィ",
         "マレーシア",
diff --git a/faker/providers/address/ko_KR/__init__.py b/faker/providers/address/ko_KR/__init__.py
index 126d9721..33af0b86 100644
--- a/faker/providers/address/ko_KR/__init__.py
+++ b/faker/providers/address/ko_KR/__init__.py
@@ -266,7 +266,7 @@ class Provider(AddressProvider):
         "리히텐슈타인",
         "마다가스카르",
         "마셜 제도",
-        "마케도니아 공화국",
+        "북마케도니아 공화국",
         "말라위",
         "말레이시아",
         "말리",
diff --git a/faker/providers/address/ne_NP/__init__.py b/faker/providers/address/ne_NP/__init__.py
index 3d6afc1c..206b40c6 100644
--- a/faker/providers/address/ne_NP/__init__.py
+++ b/faker/providers/address/ne_NP/__init__.py
@@ -230,7 +230,7 @@ class Provider(AddressProvider):
         "मौरिसनिया",
         "मौरिसस",
         "म्यानमार",
-        "म्यासेडोनिया",
+        "उत्तरी म्यासेडोनिया",
         "यमन",
         "युक्रेन",
         "युगान्डा",
diff --git a/faker/providers/address/nl_BE/__init__.py b/faker/providers/address/nl_BE/__init__.py
index d37219f9..1568d206 100644
--- a/faker/providers/address/nl_BE/__init__.py
+++ b/faker/providers/address/nl_BE/__init__.py
@@ -154,7 +154,6 @@ class Provider(AddressProvider):
         "Litouwen",
         "Luxemburg",
         "Macau",
-        "Macedonië",
         "Madagaskar",
         "Malawi",
         "Maldiven",
@@ -188,6 +187,7 @@ class Provider(AddressProvider):
         "Nigeria",
         "Niue",
         "Noord-Korea",
+        "Noord-Macedonië",
         "Noordelijke Marianen",
         "Noorwegen",
         "Norfolk",
diff --git a/faker/providers/address/nl_NL/__init__.py b/faker/providers/address/nl_NL/__init__.py
index a69463c3..d7ff67ab 100644
--- a/faker/providers/address/nl_NL/__init__.py
+++ b/faker/providers/address/nl_NL/__init__.py
@@ -153,7 +153,6 @@ class Provider(AddressProvider):
         "Litouwen",
         "Luxemburg",
         "Macau",
-        "Macedonië",
         "Madagaskar",
         "Malawi",
         "Maldiven",
@@ -187,6 +186,7 @@ class Provider(AddressProvider):
         "Nigeria",
         "Niue",
         "Noord-Korea",
+        "Noord-Macedonië",
         "Noordelijke Marianen",
         "Noorwegen",
         "Norfolk",
diff --git a/faker/providers/address/pt_BR/__init__.py b/faker/providers/address/pt_BR/__init__.py
index 2b5f239b..91ba030c 100644
--- a/faker/providers/address/pt_BR/__init__.py
+++ b/faker/providers/address/pt_BR/__init__.py
@@ -736,7 +736,7 @@ class Provider(AddressProvider):
         "Lituânia",
         "Luxemburgo",
         "Macau",
-        "Macedônia",
+        "Macedónia do Norte",
         "Madagáscar",
         "Malásia",
         "Malávi",
diff --git a/faker/providers/address/pt_PT/__init__.py b/faker/providers/address/pt_PT/__init__.py
index 71e754c7..8e559b33 100644
--- a/faker/providers/address/pt_PT/__init__.py
+++ b/faker/providers/address/pt_PT/__init__.py
@@ -325,7 +325,7 @@ class Provider(AddressProvider):
         "Lituânia",
         "Luxemburgo",
         "Macau",
-        "Macedónia",
+        "Macedónia do Norte",
         "Madagáscar",
         "Malásia",
         "Malávi",
diff --git a/faker/providers/address/sk_SK/__init__.py b/faker/providers/address/sk_SK/__init__.py
index 814575f7..e5f72d75 100644
--- a/faker/providers/address/sk_SK/__init__.py
+++ b/faker/providers/address/sk_SK/__init__.py
@@ -5009,8 +5009,6 @@ class Provider(AddressProvider):
         "Luxemburské veľkovojvodstvo",
         "Macao",
         "Osobitná administratívna oblasť Číny Macao",
-        "Macedónska republika",
-        "Bývalá juhoslovanská republika Macedónsko",
         "Madagaskar",
         "Madagaskarská republika",
         "Malawi",
@@ -5065,7 +5063,9 @@ class Provider(AddressProvider):
         "Nigérijská federatívna republika",
         "Niue",
         "Norfolk",
+        "Severné Macedónsko",
         "Severné Mariány",
+        "Severomacedónska republika",
         "Spoločenstvo Severných Marián",
         "Nórsko",
         "Nórske kráľovstvo",
diff --git a/faker/providers/address/sl_SI/__init__.py b/faker/providers/address/sl_SI/__init__.py
index efc18286..254b2fbd 100755
--- a/faker/providers/address/sl_SI/__init__.py
+++ b/faker/providers/address/sl_SI/__init__.py
@@ -1454,8 +1454,7 @@ class Provider(AddressProvider):
         "Madagaskar",
         "Republika Madagaskar",
         "Republika Madžarska",
-        "Makedonija",
-        "Republika Makedonija",
+        "Republika Severna Makedonija",
         "Malavi",
         "Maldivi",
         "Republika Maldivi",
@@ -1525,6 +1524,7 @@ class Provider(AddressProvider):
         "Republika Sejšeli",
         "Republika Senegal",
         "Severna Koreja",
+        "Severna Makedonija",
         "Sierra Leone",
         "Republika Sierra Leone",
         "Singapur",
diff --git a/faker/providers/address/sv_SE/__init__.py b/faker/providers/address/sv_SE/__init__.py
index 04ec070f..b7dbc9d4 100644
--- a/faker/providers/address/sv_SE/__init__.py
+++ b/faker/providers/address/sv_SE/__init__.py
@@ -221,7 +221,6 @@ class Provider(AddressProvider):
         "Luxemburg",
         "Macao",
         "Madagaskar",
-        "Makedonien",
         "Malawi",
         "Malaysia",
         "Maldiverna",
@@ -253,6 +252,7 @@ class Provider(AddressProvider):
         "Nigeria",
         "Niue",
         "Nordkorea",
+        "Nordmakedonien",
         "Nordmarianerna",
         "Norfolkön",
         "Norge",
diff --git a/faker/providers/address/th/__init__.py b/faker/providers/address/th/__init__.py
index e3ce41a5..7832b9cb 100644
--- a/faker/providers/address/th/__init__.py
+++ b/faker/providers/address/th/__init__.py
@@ -148,7 +148,7 @@ class Provider(AddressProvider):
         "มอลตา",
         "มัลดีฟส์",
         "มาเก๊า",
-        "มาซิโดเนีย",
+        "ประเทศมาซิโดเนียเหนือ",
         "มาดากัสการ์",
         "มายอต",
         "มาร์ตีนิก",
diff --git a/faker/providers/address/uk_UA/__init__.py b/faker/providers/address/uk_UA/__init__.py
index de4ceea6..31460933 100644
--- a/faker/providers/address/uk_UA/__init__.py
+++ b/faker/providers/address/uk_UA/__init__.py
@@ -613,7 +613,6 @@ class Provider(AddressProvider):
         "Маврикій",
         "Мавританія",
         "Мадагаскар",
-        "Республіка Македонія",
         "Малаві",
         "Малайзія",
         "Малі",
@@ -651,6 +650,7 @@ class Provider(AddressProvider):
         "Південний Судан",
         "Польща",
         "Португалія",
+        "Респу́бліка Півні́чна Македо́нія",
         "Росія",
         "Руанда",
         "Румунія",
diff --git a/faker/providers/address/zh_CN/__init__.py b/faker/providers/address/zh_CN/__init__.py
index 74de54fd..726aeea2 100644
--- a/faker/providers/address/zh_CN/__init__.py
+++ b/faker/providers/address/zh_CN/__init__.py
@@ -318,7 +318,7 @@ class Provider(AddressProvider):
         "列支敦士登",
         "立陶宛",
         "卢森堡",
-        "马其顿",
+        "北马其顿",
         "马达加斯加",
         "马拉维",
         "马来西亚",
diff --git a/faker/providers/address/zh_TW/__init__.py b/faker/providers/address/zh_TW/__init__.py
index 6ba61293..7f2decb3 100644
--- a/faker/providers/address/zh_TW/__init__.py
+++ b/faker/providers/address/zh_TW/__init__.py
@@ -291,7 +291,7 @@ class Provider(AddressProvider):
         "聖露西亞",
         "澳門",
         "聖文森及格瑞那丁",
-        "馬其頓",
+        "北馬其頓",
         "聖多美及普林西比",
         "馬達加斯加",
         "沙烏地阿拉伯",
diff --git a/faker/providers/date_time/__init__.py b/faker/providers/date_time/__init__.py
index 6172ad41..329a2840 100644
--- a/faker/providers/date_time/__init__.py
+++ b/faker/providers/date_time/__init__.py
@@ -908,7 +908,7 @@ class Provider(BaseProvider):
             alpha_2_code="MK",
             alpha_3_code="MKD",
             continent="Europe",
-            name="Macedonia",
+            name="North Macedonia",
             capital="Skopje",
         ),
         Country(
diff --git a/faker/providers/sbn/__init__.py b/faker/providers/sbn/__init__.py
new file mode 100644
index 00000000..f09eab07
--- /dev/null
+++ b/faker/providers/sbn/__init__.py
@@ -0,0 +1,53 @@
+from typing import List, Tuple
+
+from faker.providers.sbn.rules import RegistrantRule
+
+from .. import BaseProvider
+from .rules import RULES
+from .sbn import SBN, SBN9
+
+
+class Provider(BaseProvider):
+    """Generates fake SBNs. These are the precursor to the ISBN and are
+    largely similar to ISBN-10.
+
+    See https://www.isbn-international.org/content/what-isbn for the
+    format of ISBNs. SBNs have no EAN prefix or Registration Group.
+    """
+
+    def _body(self) -> List[str]:
+        """Generate the information required to create an SBN"""
+
+        reg_pub_len: int = SBN.MAX_LENGTH - 1
+
+        # Generate a registrant/publication combination
+        reg_pub: str = self.numerify("#" * reg_pub_len)
+
+        # Use rules to separate the registrant from the publication
+        rules: List[RegistrantRule] = RULES
+        registrant, publication = self._registrant_publication(reg_pub, rules)
+        return [registrant, publication]
+
+    @staticmethod
+    def _registrant_publication(reg_pub: str, rules: List[RegistrantRule]) -> Tuple[str, str]:
+        """Separate the registration from the publication in a given
+        string.
+        :param reg_pub: A string of digits representing a registration
+            and publication.
+        :param rules: A list of RegistrantRules which designate where
+            to separate the values in the string.
+        :returns: A (registrant, publication) tuple of strings.
+        """
+        for rule in rules:
+            if rule.min <= reg_pub[:-1] <= rule.max:
+                reg_len = rule.registrant_length
+                break
+        else:
+            raise Exception("Registrant/Publication not found in registrant " "rule list.")
+        registrant, publication = reg_pub[:reg_len], reg_pub[reg_len:]
+        return registrant, publication
+
+    def sbn9(self, separator: str = "-") -> str:
+        registrant, publication = self._body()
+        sbn = SBN9(registrant, publication)
+        return sbn.format(separator)
diff --git a/faker/providers/sbn/en_US/__init__.py b/faker/providers/sbn/en_US/__init__.py
new file mode 100644
index 00000000..42616448
--- /dev/null
+++ b/faker/providers/sbn/en_US/__init__.py
@@ -0,0 +1,5 @@
+from .. import Provider as SBNProvider
+
+
+class Provider(SBNProvider):
+    pass
diff --git a/faker/providers/sbn/rules.py b/faker/providers/sbn/rules.py
new file mode 100644
index 00000000..aaf32fd9
--- /dev/null
+++ b/faker/providers/sbn/rules.py
@@ -0,0 +1,24 @@
+"""
+This module exists solely to figure how long a registrant/publication
+number may be within an SBN. It's the same as the ISBN implementation
+for ean 978, reg_group 0.
+"""
+
+from collections import namedtuple
+from typing import List
+
+RegistrantRule = namedtuple("RegistrantRule", ["min", "max", "registrant_length"])
+
+# Structure: RULES = [Rule1, Rule2, ...]
+RULES: List[RegistrantRule] = [
+    RegistrantRule("0000000", "1999999", 2),
+    RegistrantRule("2000000", "2279999", 3),
+    RegistrantRule("2280000", "2289999", 4),
+    RegistrantRule("2290000", "6479999", 3),
+    RegistrantRule("6480000", "6489999", 7),
+    RegistrantRule("6490000", "6999999", 3),
+    RegistrantRule("7000000", "8499999", 4),
+    RegistrantRule("8500000", "8999999", 5),
+    RegistrantRule("9000000", "9499999", 6),
+    RegistrantRule("9500000", "9999999", 7),
+]
diff --git a/faker/providers/sbn/sbn.py b/faker/providers/sbn/sbn.py
new file mode 100644
index 00000000..070f799b
--- /dev/null
+++ b/faker/providers/sbn/sbn.py
@@ -0,0 +1,49 @@
+"""
+This module is responsible for generating the check digit and formatting
+SBN numbers.
+"""
+from typing import Any, Optional
+
+
+class SBN:
+    MAX_LENGTH = 9
+
+    def __init__(
+        self,
+        registrant: Optional[str] = None,
+        publication: Optional[str] = None,
+    ) -> None:
+        self.registrant = registrant
+        self.publication = publication
+
+
+class SBN9(SBN):
+    def __init__(self, *args: Any, **kwargs: Any) -> None:
+        super().__init__(*args, **kwargs)
+        self.check_digit = self._check_digit()
+
+    def _check_digit(self) -> str:
+        """Calculate the check digit for SBN-9.
+        SBNs use the same check digit calculation as ISBN. See
+        https://en.wikipedia.org/wiki/International_Standard_Book_Number
+                for calculation. Only modification is weights range from 1 to 9
+                instead of 1 to 10.
+        """
+        weights = range(1, 9)
+        body = "".join([part for part in [self.registrant, self.publication] if part is not None])
+        remainder = sum(int(b) * w for b, w in zip(body, weights)) % 11
+        check_digit = "X" if remainder == 10 else str(remainder)
+        return str(check_digit)
+
+    def format(self, separator: str = "") -> str:
+        return separator.join(
+            [
+                part
+                for part in [
+                    self.registrant,
+                    self.publication,
+                    self.check_digit,
+                ]
+                if part is not None
+            ]
+        )


Test patch:
diff --git a/tests/providers/test_sbn.py b/tests/providers/test_sbn.py
new file mode 100644
index 00000000..9048b649
--- /dev/null
+++ b/tests/providers/test_sbn.py
@@ -0,0 +1,62 @@
+import pytest
+
+from faker.providers.sbn import SBN9
+from faker.providers.sbn.en_US import Provider as SBNProvider
+from faker.providers.sbn.rules import RegistrantRule
+
+
+class TestISBN9:
+    def test_check_digit_is_correct(self):
+        sbn = SBN9(registrant="340", publication="01381")
+        assert sbn.check_digit == "X"
+        sbn = SBN9(registrant="06", publication="230125")
+        assert sbn.check_digit == "2"
+        sbn = SBN9(registrant="10103", publication="202")
+        assert sbn.check_digit == "3"
+
+    def test_format_length(self):
+        sbn = SBN9(registrant="4516", publication="7331")
+        assert len(sbn.format()) == 9
+        sbn = SBN9(registrant="451", publication="10036")
+        assert len(sbn.format()) == 9
+
+
+class TestProvider:
+    prov = SBNProvider(None)
+
+    def test_reg_pub_separation(self):
+        r1 = RegistrantRule("0000000", "0000001", 1)
+        r2 = RegistrantRule("0000002", "0000003", 2)
+        assert self.prov._registrant_publication("00000000", [r1, r2]) == (
+            "0",
+            "0000000",
+        )
+        assert self.prov._registrant_publication("00000010", [r1, r2]) == (
+            "0",
+            "0000010",
+        )
+        assert self.prov._registrant_publication("00000019", [r1, r2]) == (
+            "0",
+            "0000019",
+        )
+        assert self.prov._registrant_publication("00000020", [r1, r2]) == (
+            "00",
+            "000020",
+        )
+        assert self.prov._registrant_publication("00000030", [r1, r2]) == (
+            "00",
+            "000030",
+        )
+        assert self.prov._registrant_publication("00000031", [r1, r2]) == (
+            "00",
+            "000031",
+        )
+        assert self.prov._registrant_publication("00000039", [r1, r2]) == (
+            "00",
+            "000039",
+        )
+
+    def test_rule_not_found(self):
+        with pytest.raises(Exception):
+            r = RegistrantRule("0000000", "0000001", 1)
+            self.prov._registrant_publication("0000002", [r])
diff --git a/tests/utils/test_utils.py b/tests/utils/test_utils.py
index cd3613d9..c07b9081 100644
--- a/tests/utils/test_utils.py
+++ b/tests/utils/test_utils.py
@@ -91,6 +91,7 @@ class UtilsTestCase(unittest.TestCase):
                     "faker.providers.phone_number",
                     "faker.providers.profile",
                     "faker.providers.python",
+                    "faker.providers.sbn",
                     "faker.providers.ssn",
                     "faker.providers.user_agent",
                 ],