scriptconv 0.0.2a1__tar.gz → 0.0.3a1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/PKG-INFO +27 -11
  2. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/README.md +24 -8
  3. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/pyproject.toml +6 -2
  4. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv/__init__.py +4 -0
  5. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv/notation.py +130 -0
  6. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv/version.py +1 -1
  7. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv.egg-info/PKG-INFO +27 -11
  8. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/tests/test_examples.py +6 -0
  9. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/tests/test_notation.py +41 -1
  10. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/LICENSE +0 -0
  11. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/requirements.txt +0 -0
  12. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv/__main__.py +0 -0
  13. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv/py.typed +0 -0
  14. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv/scripts.py +0 -0
  15. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv/translit.py +0 -0
  16. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv.egg-info/SOURCES.txt +0 -0
  17. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv.egg-info/dependency_links.txt +0 -0
  18. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv.egg-info/requires.txt +0 -0
  19. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/scriptconv.egg-info/top_level.txt +0 -0
  20. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/setup.cfg +0 -0
  21. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/tests/test_cli.py +0 -0
  22. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/tests/test_scripts.py +0 -0
  23. {scriptconv-0.0.2a1 → scriptconv-0.0.3a1}/tests/test_translit.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scriptconv
3
- Version: 0.0.2a1
4
- Summary: Shared script-conversion core — ISO-15924 detection, IPA↔ARPA/X-SAMPA/Lexique, Buckwalter, Hangul→jamo
3
+ Version: 0.0.3a1
4
+ Summary: Zero-dependency script & phoneme-notation core — ISO-15924 detection & metadata, IPA↔ARPABET/X-SAMPA/Lexique/Kirshenbaum/Cotovía/RFE, Buckwalter↔Arabic, Hangul→jamo, kana
5
5
  License: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/TigreGotico/scriptconv
7
7
  Project-URL: Issues, https://github.com/TigreGotico/scriptconv/issues
8
- Keywords: ipa,arpabet,x-sampa,lexique,buckwalter,hangul,script,iso15924,tts,g2p,phoneme
8
+ Keywords: ipa,arpabet,x-sampa,kirshenbaum,cotovia,rfe,lexique,buckwalter,hangul,jamo,kana,transliteration,notation,phoneme,phonetic-alphabet,script,iso15924,unicode,tts,g2p
9
9
  Classifier: Development Status :: 3 - Alpha
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: Intended Audience :: Science/Research
@@ -31,12 +31,21 @@ Dynamic: license-file
31
31
  [![Build Tests](https://github.com/TigreGotico/scriptconv/actions/workflows/build-tests.yml/badge.svg?branch=dev)](https://github.com/TigreGotico/scriptconv/actions/workflows/build-tests.yml)
32
32
  [![PyPI version](https://img.shields.io/pypi/v/scriptconv.svg)](https://pypi.org/project/scriptconv/)
33
33
 
34
- **scriptconv** is a zero-dependency Python library for written-script operations:
35
- ISO-15924 script identification and metadata, character-range detection, language-to-script
36
- mapping, phoneme-notation transcoding (IPA ↔ ARPABET / X-SAMPA / Lexique / Kirshenbaum / Cotovía,
37
- Buckwalter Arabic script), and orthographic decomposition of Hangul syllable blocks into
38
- jamo letters. Every conversion is a pure data table or arithmetic operation; no linguistic
39
- rules, no external files, no runtime dependencies beyond the Python standard library.
34
+ **scriptconv** is a zero-dependency Python library for written-script and
35
+ phoneme-notation operations:
36
+
37
+ - **Script identification & metadata** ISO-15924 detection, character-range
38
+ lookup, typological `script_type`, base direction, mixed-script segmentation
39
+ (`script_runs`), and language script mapping.
40
+ - **Phoneme-notation transcoding** — IPA ↔ ARPABET, X-SAMPA, Lexique,
41
+ Kirshenbaum, Cotovía and RFE, routed through IPA, with queryable per-notation
42
+ fidelity metadata (`NOTATION_INFO`) and a `looks_like_ipa` detector.
43
+ - **Script transliteration & decomposition** — Buckwalter ↔ Arabic script,
44
+ Hangul → jamo (compatibility or conjoining), Hiragana ↔ Katakana.
45
+
46
+ Every conversion is a pure data table or arithmetic operation — **no
47
+ phonemization**, no linguistic rules, no external files, and no runtime
48
+ dependencies beyond the Python standard library.
40
49
 
41
50
  Transcoding is reversible where the target inventory permits — see
42
51
  [Fidelity guarantees](#fidelity-guarantees) for the exact per-notation guarantees.
@@ -75,7 +84,8 @@ from scriptconv import (
75
84
  xsampa_to_ipa, ipa_to_xsampa,
76
85
  buckwalter_to_arabic, arabic_to_buckwalter,
77
86
  lexique_to_ipa, ipa_to_lexique,
78
- kirshenbaum_to_ipa, ipa_to_kirshenbaum, cotovia_to_ipa, ipa_to_cotovia, looks_like_ipa,
87
+ kirshenbaum_to_ipa, ipa_to_kirshenbaum, cotovia_to_ipa, ipa_to_cotovia,
88
+ rfe_to_ipa, ipa_to_rfe, looks_like_ipa,
79
89
  decompose_hangul, hira_to_kana, kana_to_hira,
80
90
  convert, can_convert, convert_batch, Notation, NOTATION_INFO,
81
91
  )
@@ -110,6 +120,9 @@ ipa_to_kirshenbaum("ŋ") # "N"
110
120
  cotovia_to_ipa("karro") # "karo" (Galician Cotovía TTS notation)
111
121
  ipa_to_cotovia("ʎ") # "L"
112
122
 
123
+ rfe_to_ipa("kaša") # "kaʃa" (Spanish/Romance RFE alphabet)
124
+ ipa_to_rfe("ɲ") # "ñ"
125
+
113
126
  looks_like_ipa("pʰɑtʃ") # True (heuristic: has IPA-distinctive symbols)
114
127
  looks_like_ipa("hello") # False
115
128
 
@@ -142,7 +155,7 @@ python -m scriptconv lang ko
142
155
  | Module | Contents |
143
156
  |--------|----------|
144
157
  | `scriptconv.scripts` | `Script` dataclass (with `script_type`), `SCRIPT_REGISTRY` (34 scripts), `detect_script`, `char_script`, `script_distribution`, `script_runs`, `base_direction`, `lang_to_script`, `script_to_langs`, `normalize_script_tag` |
145
- | `scriptconv.notation` | `Notation` enum, `NotationInfo`/`NOTATION_INFO` fidelity registry, `convert` facade, `can_convert` predicate, `convert_batch` generator, pair-wise converters (ARPABET ↔ IPA, X-SAMPA ↔ IPA, Buckwalter ↔ Arabic, Lexique ↔ IPA, Kirshenbaum ↔ IPA, Cotovía ↔ IPA), `looks_like_ipa` detector |
158
+ | `scriptconv.notation` | `Notation` enum, `NotationInfo`/`NOTATION_INFO` fidelity registry, `convert` facade, `can_convert` predicate, `convert_batch` generator, pair-wise converters (ARPABET ↔ IPA, X-SAMPA ↔ IPA, Buckwalter ↔ Arabic, Lexique ↔ IPA, Kirshenbaum ↔ IPA, Cotovía ↔ IPA, RFE ↔ IPA), `looks_like_ipa` detector |
146
159
  | `scriptconv.translit` | `decompose_hangul` (Hangul blocks → jamo, compatibility or conjoining), `hira_to_kana`/`kana_to_hira` — all orthographic only |
147
160
 
148
161
  ## Documentation
@@ -172,6 +185,7 @@ Runnable scripts in [examples/](examples/):
172
185
  | `13_script_runs.py` | Per-script segmentation of mixed-script text |
173
186
  | `14_kana_transliteration.py` | Hiragana ↔ Katakana |
174
187
  | `15_cotovia.py` | Cotovía (Galician TTS notation) ↔ IPA |
188
+ | `16_rfe.py` | RFE (Spanish/Romance philology alphabet) ↔ IPA |
175
189
 
176
190
  ## Fidelity guarantees
177
191
 
@@ -187,6 +201,7 @@ round-trip is exact and what happens to a symbol the table does not know.
187
201
  | **Lexique ↔ IPA** | Exact except the `°`/`3` schwa pair (both → `ə`; reverse always → `°`) | Exact | Passed through unchanged |
188
202
  | **Kirshenbaum ↔ IPA** | Exact | **Lossy** — restricted ASCII inventory; IPA outside it passes through | Passed through unchanged |
189
203
  | **Cotovía ↔ IPA** | Exact except the three `L`/`Z`/`jj` symbols for `ʎ` normalise to `L` | **Lossy** — Galician/Spanish inventory; IPA outside it passes through | Passed through unchanged |
204
+ | **RFE ↔ IPA** | Exact except `ñ`/`n̮` for `ɲ` normalise to `ñ` | **Lossy** — core Spanish/Romance inventory; IPA outside it passes through | Passed through unchanged |
190
205
 
191
206
  This table is also available programmatically via `NOTATION_INFO`
192
207
  (`NotationInfo` records with `lossless_to_ipa`, `lossless_from_ipa`,
@@ -213,4 +228,5 @@ Derived tables used internally:
213
228
  | Lexique phoneme codes | New, B. & Pallier, C. — *Manuel de Lexique 3* v3.11, Tableau 2; [chrplr/openlexicon](https://github.com/chrplr/openlexicon) | CC BY-SA 4.0 |
214
229
  | Kirshenbaum ↔ IPA | Kirshenbaum 1993 ASCII-IPA standard (comp.speech), cross-checked against espeak-ng | — (factual symbol mapping) |
215
230
  | Cotovía ↔ IPA | Universidade de Vigo GTM Cotovía TTS project (`fonemas.cpp`) | — (factual symbol mapping) |
231
+ | RFE ↔ IPA | RFE phonetic alphabet (Revista de Filología Española, 1915) | — (factual symbol mapping) |
216
232
  | Hangul jamo tables | [stannam/hangul_to_ipa](https://github.com/stannam/hangul_to_ipa) | — |
@@ -4,12 +4,21 @@
4
4
  [![Build Tests](https://github.com/TigreGotico/scriptconv/actions/workflows/build-tests.yml/badge.svg?branch=dev)](https://github.com/TigreGotico/scriptconv/actions/workflows/build-tests.yml)
5
5
  [![PyPI version](https://img.shields.io/pypi/v/scriptconv.svg)](https://pypi.org/project/scriptconv/)
6
6
 
7
- **scriptconv** is a zero-dependency Python library for written-script operations:
8
- ISO-15924 script identification and metadata, character-range detection, language-to-script
9
- mapping, phoneme-notation transcoding (IPA ↔ ARPABET / X-SAMPA / Lexique / Kirshenbaum / Cotovía,
10
- Buckwalter Arabic script), and orthographic decomposition of Hangul syllable blocks into
11
- jamo letters. Every conversion is a pure data table or arithmetic operation; no linguistic
12
- rules, no external files, no runtime dependencies beyond the Python standard library.
7
+ **scriptconv** is a zero-dependency Python library for written-script and
8
+ phoneme-notation operations:
9
+
10
+ - **Script identification & metadata** ISO-15924 detection, character-range
11
+ lookup, typological `script_type`, base direction, mixed-script segmentation
12
+ (`script_runs`), and language script mapping.
13
+ - **Phoneme-notation transcoding** — IPA ↔ ARPABET, X-SAMPA, Lexique,
14
+ Kirshenbaum, Cotovía and RFE, routed through IPA, with queryable per-notation
15
+ fidelity metadata (`NOTATION_INFO`) and a `looks_like_ipa` detector.
16
+ - **Script transliteration & decomposition** — Buckwalter ↔ Arabic script,
17
+ Hangul → jamo (compatibility or conjoining), Hiragana ↔ Katakana.
18
+
19
+ Every conversion is a pure data table or arithmetic operation — **no
20
+ phonemization**, no linguistic rules, no external files, and no runtime
21
+ dependencies beyond the Python standard library.
13
22
 
14
23
  Transcoding is reversible where the target inventory permits — see
15
24
  [Fidelity guarantees](#fidelity-guarantees) for the exact per-notation guarantees.
@@ -48,7 +57,8 @@ from scriptconv import (
48
57
  xsampa_to_ipa, ipa_to_xsampa,
49
58
  buckwalter_to_arabic, arabic_to_buckwalter,
50
59
  lexique_to_ipa, ipa_to_lexique,
51
- kirshenbaum_to_ipa, ipa_to_kirshenbaum, cotovia_to_ipa, ipa_to_cotovia, looks_like_ipa,
60
+ kirshenbaum_to_ipa, ipa_to_kirshenbaum, cotovia_to_ipa, ipa_to_cotovia,
61
+ rfe_to_ipa, ipa_to_rfe, looks_like_ipa,
52
62
  decompose_hangul, hira_to_kana, kana_to_hira,
53
63
  convert, can_convert, convert_batch, Notation, NOTATION_INFO,
54
64
  )
@@ -83,6 +93,9 @@ ipa_to_kirshenbaum("ŋ") # "N"
83
93
  cotovia_to_ipa("karro") # "karo" (Galician Cotovía TTS notation)
84
94
  ipa_to_cotovia("ʎ") # "L"
85
95
 
96
+ rfe_to_ipa("kaša") # "kaʃa" (Spanish/Romance RFE alphabet)
97
+ ipa_to_rfe("ɲ") # "ñ"
98
+
86
99
  looks_like_ipa("pʰɑtʃ") # True (heuristic: has IPA-distinctive symbols)
87
100
  looks_like_ipa("hello") # False
88
101
 
@@ -115,7 +128,7 @@ python -m scriptconv lang ko
115
128
  | Module | Contents |
116
129
  |--------|----------|
117
130
  | `scriptconv.scripts` | `Script` dataclass (with `script_type`), `SCRIPT_REGISTRY` (34 scripts), `detect_script`, `char_script`, `script_distribution`, `script_runs`, `base_direction`, `lang_to_script`, `script_to_langs`, `normalize_script_tag` |
118
- | `scriptconv.notation` | `Notation` enum, `NotationInfo`/`NOTATION_INFO` fidelity registry, `convert` facade, `can_convert` predicate, `convert_batch` generator, pair-wise converters (ARPABET ↔ IPA, X-SAMPA ↔ IPA, Buckwalter ↔ Arabic, Lexique ↔ IPA, Kirshenbaum ↔ IPA, Cotovía ↔ IPA), `looks_like_ipa` detector |
131
+ | `scriptconv.notation` | `Notation` enum, `NotationInfo`/`NOTATION_INFO` fidelity registry, `convert` facade, `can_convert` predicate, `convert_batch` generator, pair-wise converters (ARPABET ↔ IPA, X-SAMPA ↔ IPA, Buckwalter ↔ Arabic, Lexique ↔ IPA, Kirshenbaum ↔ IPA, Cotovía ↔ IPA, RFE ↔ IPA), `looks_like_ipa` detector |
119
132
  | `scriptconv.translit` | `decompose_hangul` (Hangul blocks → jamo, compatibility or conjoining), `hira_to_kana`/`kana_to_hira` — all orthographic only |
120
133
 
121
134
  ## Documentation
@@ -145,6 +158,7 @@ Runnable scripts in [examples/](examples/):
145
158
  | `13_script_runs.py` | Per-script segmentation of mixed-script text |
146
159
  | `14_kana_transliteration.py` | Hiragana ↔ Katakana |
147
160
  | `15_cotovia.py` | Cotovía (Galician TTS notation) ↔ IPA |
161
+ | `16_rfe.py` | RFE (Spanish/Romance philology alphabet) ↔ IPA |
148
162
 
149
163
  ## Fidelity guarantees
150
164
 
@@ -160,6 +174,7 @@ round-trip is exact and what happens to a symbol the table does not know.
160
174
  | **Lexique ↔ IPA** | Exact except the `°`/`3` schwa pair (both → `ə`; reverse always → `°`) | Exact | Passed through unchanged |
161
175
  | **Kirshenbaum ↔ IPA** | Exact | **Lossy** — restricted ASCII inventory; IPA outside it passes through | Passed through unchanged |
162
176
  | **Cotovía ↔ IPA** | Exact except the three `L`/`Z`/`jj` symbols for `ʎ` normalise to `L` | **Lossy** — Galician/Spanish inventory; IPA outside it passes through | Passed through unchanged |
177
+ | **RFE ↔ IPA** | Exact except `ñ`/`n̮` for `ɲ` normalise to `ñ` | **Lossy** — core Spanish/Romance inventory; IPA outside it passes through | Passed through unchanged |
163
178
 
164
179
  This table is also available programmatically via `NOTATION_INFO`
165
180
  (`NotationInfo` records with `lossless_to_ipa`, `lossless_from_ipa`,
@@ -186,4 +201,5 @@ Derived tables used internally:
186
201
  | Lexique phoneme codes | New, B. & Pallier, C. — *Manuel de Lexique 3* v3.11, Tableau 2; [chrplr/openlexicon](https://github.com/chrplr/openlexicon) | CC BY-SA 4.0 |
187
202
  | Kirshenbaum ↔ IPA | Kirshenbaum 1993 ASCII-IPA standard (comp.speech), cross-checked against espeak-ng | — (factual symbol mapping) |
188
203
  | Cotovía ↔ IPA | Universidade de Vigo GTM Cotovía TTS project (`fonemas.cpp`) | — (factual symbol mapping) |
204
+ | RFE ↔ IPA | RFE phonetic alphabet (Revista de Filología Española, 1915) | — (factual symbol mapping) |
189
205
  | Hangul jamo tables | [stannam/hangul_to_ipa](https://github.com/stannam/hangul_to_ipa) | — |
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "scriptconv"
7
7
  dynamic = ["version", "dependencies"]
8
- description = "Shared script-conversion core — ISO-15924 detection, IPA↔ARPA/X-SAMPA/Lexique, Buckwalter, Hangul→jamo"
8
+ description = "Zero-dependency script & phoneme-notation core — ISO-15924 detection & metadata, IPA↔ARPABET/X-SAMPA/Lexique/Kirshenbaum/Cotovía/RFE, Buckwalter↔Arabic, Hangul→jamo, kana"
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}
11
11
  requires-python = ">=3.10"
@@ -22,7 +22,11 @@ classifiers = [
22
22
  "License :: OSI Approved :: Apache Software License",
23
23
  "Operating System :: OS Independent",
24
24
  ]
25
- keywords = ["ipa", "arpabet", "x-sampa", "lexique", "buckwalter", "hangul", "script", "iso15924", "tts", "g2p", "phoneme"]
25
+ keywords = [
26
+ "ipa", "arpabet", "x-sampa", "kirshenbaum", "cotovia", "rfe", "lexique",
27
+ "buckwalter", "hangul", "jamo", "kana", "transliteration", "notation",
28
+ "phoneme", "phonetic-alphabet", "script", "iso15924", "unicode", "tts", "g2p",
29
+ ]
26
30
 
27
31
  [tool.setuptools.dynamic]
28
32
  version = {attr = "scriptconv.version.VERSION_STR"}
@@ -52,6 +52,8 @@ from scriptconv.notation import (
52
52
  ipa_to_kirshenbaum,
53
53
  cotovia_to_ipa,
54
54
  ipa_to_cotovia,
55
+ rfe_to_ipa,
56
+ ipa_to_rfe,
55
57
  looks_like_ipa,
56
58
  )
57
59
  from scriptconv.translit import (
@@ -91,6 +93,8 @@ __all__ = [
91
93
  "ipa_to_kirshenbaum",
92
94
  "cotovia_to_ipa",
93
95
  "ipa_to_cotovia",
96
+ "rfe_to_ipa",
97
+ "ipa_to_rfe",
94
98
  "looks_like_ipa",
95
99
  # translit
96
100
  "decompose_hangul",
@@ -39,6 +39,8 @@ __all__ = [
39
39
  "ipa_to_kirshenbaum",
40
40
  "cotovia_to_ipa",
41
41
  "ipa_to_cotovia",
42
+ "rfe_to_ipa",
43
+ "ipa_to_rfe",
42
44
  "looks_like_ipa",
43
45
  ]
44
46
 
@@ -54,6 +56,7 @@ class Notation(str, Enum):
54
56
  LEXIQUE = "lexique" # Lexique one-char-per-phoneme French notation
55
57
  KIRSHENBAUM = "kirshenbaum" # ASCII-IPA (espeak-ng native notation)
56
58
  COTOVIA = "cotovia" # Universidade de Vigo Cotovía TTS notation (gl)
59
+ RFE = "rfe" # Revista de Filología Española phonetic alphabet
57
60
 
58
61
  def __repr__(self) -> str:
59
62
  return f"Notation.{self.name}"
@@ -786,6 +789,126 @@ def ipa_to_cotovia(ipa: str) -> str:
786
789
  return "".join(result)
787
790
 
788
791
 
792
+ # ---------------------------------------------------------------------------
793
+ # RFE (Revista de Filología Española) ↔ IPA
794
+ #
795
+ # The RFE phonetic alphabet (Navarro Tomás, Revista de Filología Española,
796
+ # 1915) is the traditional transcription system of Spanish and Romance
797
+ # philology. This is its core, well-attested inventory; rare interdental and
798
+ # variant diacritic symbols from the full standard are omitted. Symbols are
799
+ # matched longest-first (combining-mark symbols before their base letters).
800
+ # Reference: RFE Phonetic Alphabet
801
+ # (https://en.wikipedia.org/wiki/RFE_Phonetic_Alphabet).
802
+ # ---------------------------------------------------------------------------
803
+
804
+ _RFE_TO_IPA: dict[str, str] = {
805
+ # Combining-mark symbols (longest-match first)
806
+ "r̄": "r", # r + macron = alveolar trill (plain r = tap ɾ)
807
+ "n̮": "ɲ", # n + breve below = palatal nasal ɲ
808
+ "l̮": "ʎ", # l + breve below = palatal lateral ʎ
809
+ # Palatal / postalveolar
810
+ "ĉ": "tʃ", # ĉ = tʃ
811
+ "š": "ʃ", # š = ʃ
812
+ "ž": "ʒ", # ž = ʒ
813
+ "ŷ": "ɟʝ", # ŷ = ɟʝ (voiced palatal affricate)
814
+ "ñ": "ɲ", # ñ = ɲ
815
+ "y": "ʝ", # y = ʝ
816
+ "j": "j", # j = j
817
+ # Spanish approximant/fricative allophones
818
+ "ƀ": "β", # ƀ = β
819
+ "đ": "ð", # đ = ð
820
+ "ǥ": "ɣ", # ǥ = ɣ
821
+ # Other consonants
822
+ "θ": "θ", # θ = θ
823
+ "x": "x",
824
+ "ł": "ɫ", # ł = ɫ (velarized l)
825
+ "ŋ": "ŋ", # ŋ = ŋ
826
+ "w": "w",
827
+ "h": "h",
828
+ "b": "b",
829
+ "p": "p",
830
+ "t": "t",
831
+ "d": "d",
832
+ "k": "k",
833
+ "g": "ɡ", # g = ɡ (script g, matching the other tables)
834
+ "f": "f",
835
+ "v": "v",
836
+ "s": "s",
837
+ "z": "z",
838
+ "m": "m",
839
+ "n": "n",
840
+ "l": "l",
841
+ "r": "ɾ", # r = tap ɾ
842
+ # Vowels
843
+ "a": "a", "e": "e", "i": "i", "o": "o", "u": "u",
844
+ "ə": "ə", # ə = ə
845
+ }
846
+
847
+ # Reverse: IPA → RFE. First-wins deduplicates; pin the canonical RFE spellings
848
+ # for the palatal nasal (ñ) and the trill/tap pair.
849
+ _IPA_TO_RFE: dict[str, str] = {}
850
+ for _rfe, _ip in _RFE_TO_IPA.items():
851
+ _IPA_TO_RFE.setdefault(_ip, _rfe)
852
+ _IPA_TO_RFE["ɲ"] = "ñ" # ɲ → ñ (canonical, not the n̮ variant)
853
+
854
+ _RFE_KEYS_SORTED = sorted(_RFE_TO_IPA.keys(), key=len, reverse=True)
855
+ _RFE_RE = re.compile("|".join(re.escape(x) for x in _RFE_KEYS_SORTED))
856
+ _IPA_RFE_KEYS_SORTED = sorted(_IPA_TO_RFE.keys(), key=len, reverse=True)
857
+ _IPA_RFE_RE = re.compile("|".join(re.escape(x) for x in _IPA_RFE_KEYS_SORTED))
858
+
859
+
860
+ def rfe_to_ipa(rfe: str) -> str:
861
+ """Convert an RFE (Revista de Filología Española) string to IPA.
862
+
863
+ Multi-character symbols are matched longest-first. Characters outside the
864
+ table pass through unchanged.
865
+
866
+ Examples
867
+ --------
868
+ >>> rfe_to_ipa("š")
869
+ 'ʃ'
870
+ >>> rfe_to_ipa("kaša")
871
+ 'kaʃa'
872
+ """
873
+ result = []
874
+ pos = 0
875
+ while pos < len(rfe):
876
+ m = _RFE_RE.match(rfe, pos)
877
+ if m:
878
+ result.append(_RFE_TO_IPA[m.group(0)])
879
+ pos = m.end()
880
+ else:
881
+ result.append(rfe[pos])
882
+ pos += 1
883
+ return "".join(result)
884
+
885
+
886
+ def ipa_to_rfe(ipa: str) -> str:
887
+ """Convert an IPA string to RFE (Revista de Filología Española) notation.
888
+
889
+ Multi-character IPA symbols are matched longest-first. Characters outside
890
+ the table pass through unchanged.
891
+
892
+ Examples
893
+ --------
894
+ >>> ipa_to_rfe("ʃ")
895
+ 'š'
896
+ >>> ipa_to_rfe("ɲ")
897
+ 'ñ'
898
+ """
899
+ result = []
900
+ pos = 0
901
+ while pos < len(ipa):
902
+ m = _IPA_RFE_RE.match(ipa, pos)
903
+ if m:
904
+ result.append(_IPA_TO_RFE[m.group(0)])
905
+ pos = m.end()
906
+ else:
907
+ result.append(ipa[pos])
908
+ pos += 1
909
+ return "".join(result)
910
+
911
+
789
912
  # ---------------------------------------------------------------------------
790
913
  # convert — facade routing through IPA where no direct map exists
791
914
  # ---------------------------------------------------------------------------
@@ -857,6 +980,7 @@ _TO_IPA: dict[Notation, "callable"] = {
857
980
  Notation.LEXIQUE: lexique_to_ipa,
858
981
  Notation.KIRSHENBAUM: kirshenbaum_to_ipa,
859
982
  Notation.COTOVIA: cotovia_to_ipa,
983
+ Notation.RFE: rfe_to_ipa,
860
984
  }
861
985
  _FROM_IPA: dict[Notation, "callable"] = {
862
986
  Notation.ARPA: ipa_to_arpa,
@@ -864,6 +988,7 @@ _FROM_IPA: dict[Notation, "callable"] = {
864
988
  Notation.LEXIQUE: ipa_to_lexique,
865
989
  Notation.KIRSHENBAUM: ipa_to_kirshenbaum,
866
990
  Notation.COTOVIA: ipa_to_cotovia,
991
+ Notation.RFE: ipa_to_rfe,
867
992
  }
868
993
  _DIRECT_PAIRS: dict[tuple[Notation, Notation], "callable"] = {
869
994
  (Notation.BUCKWALTER, Notation.ARABIC): buckwalter_to_arabic,
@@ -974,6 +1099,11 @@ NOTATION_INFO: dict[Notation, NotationInfo] = {
974
1099
  token_separated=False,
975
1100
  reference="Universidade de Vigo GTM Cotovía TTS (fonemas.cpp)",
976
1101
  ),
1102
+ Notation.RFE: NotationInfo(
1103
+ Notation.RFE, lossless_to_ipa=False, lossless_from_ipa=False,
1104
+ token_separated=False,
1105
+ reference="RFE phonetic alphabet (Revista de Filología Española, 1915)",
1106
+ ),
977
1107
  Notation.BUCKWALTER: NotationInfo(
978
1108
  Notation.BUCKWALTER, lossless_to_ipa=True, lossless_from_ipa=False,
979
1109
  token_separated=False,
@@ -1,7 +1,7 @@
1
1
  # START_VERSION_BLOCK
2
2
  VERSION_MAJOR = 0
3
3
  VERSION_MINOR = 0
4
- VERSION_BUILD = 2
4
+ VERSION_BUILD = 3
5
5
  VERSION_ALPHA = 1
6
6
  # END_VERSION_BLOCK
7
7
 
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scriptconv
3
- Version: 0.0.2a1
4
- Summary: Shared script-conversion core — ISO-15924 detection, IPA↔ARPA/X-SAMPA/Lexique, Buckwalter, Hangul→jamo
3
+ Version: 0.0.3a1
4
+ Summary: Zero-dependency script & phoneme-notation core — ISO-15924 detection & metadata, IPA↔ARPABET/X-SAMPA/Lexique/Kirshenbaum/Cotovía/RFE, Buckwalter↔Arabic, Hangul→jamo, kana
5
5
  License: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/TigreGotico/scriptconv
7
7
  Project-URL: Issues, https://github.com/TigreGotico/scriptconv/issues
8
- Keywords: ipa,arpabet,x-sampa,lexique,buckwalter,hangul,script,iso15924,tts,g2p,phoneme
8
+ Keywords: ipa,arpabet,x-sampa,kirshenbaum,cotovia,rfe,lexique,buckwalter,hangul,jamo,kana,transliteration,notation,phoneme,phonetic-alphabet,script,iso15924,unicode,tts,g2p
9
9
  Classifier: Development Status :: 3 - Alpha
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: Intended Audience :: Science/Research
@@ -31,12 +31,21 @@ Dynamic: license-file
31
31
  [![Build Tests](https://github.com/TigreGotico/scriptconv/actions/workflows/build-tests.yml/badge.svg?branch=dev)](https://github.com/TigreGotico/scriptconv/actions/workflows/build-tests.yml)
32
32
  [![PyPI version](https://img.shields.io/pypi/v/scriptconv.svg)](https://pypi.org/project/scriptconv/)
33
33
 
34
- **scriptconv** is a zero-dependency Python library for written-script operations:
35
- ISO-15924 script identification and metadata, character-range detection, language-to-script
36
- mapping, phoneme-notation transcoding (IPA ↔ ARPABET / X-SAMPA / Lexique / Kirshenbaum / Cotovía,
37
- Buckwalter Arabic script), and orthographic decomposition of Hangul syllable blocks into
38
- jamo letters. Every conversion is a pure data table or arithmetic operation; no linguistic
39
- rules, no external files, no runtime dependencies beyond the Python standard library.
34
+ **scriptconv** is a zero-dependency Python library for written-script and
35
+ phoneme-notation operations:
36
+
37
+ - **Script identification & metadata** ISO-15924 detection, character-range
38
+ lookup, typological `script_type`, base direction, mixed-script segmentation
39
+ (`script_runs`), and language script mapping.
40
+ - **Phoneme-notation transcoding** — IPA ↔ ARPABET, X-SAMPA, Lexique,
41
+ Kirshenbaum, Cotovía and RFE, routed through IPA, with queryable per-notation
42
+ fidelity metadata (`NOTATION_INFO`) and a `looks_like_ipa` detector.
43
+ - **Script transliteration & decomposition** — Buckwalter ↔ Arabic script,
44
+ Hangul → jamo (compatibility or conjoining), Hiragana ↔ Katakana.
45
+
46
+ Every conversion is a pure data table or arithmetic operation — **no
47
+ phonemization**, no linguistic rules, no external files, and no runtime
48
+ dependencies beyond the Python standard library.
40
49
 
41
50
  Transcoding is reversible where the target inventory permits — see
42
51
  [Fidelity guarantees](#fidelity-guarantees) for the exact per-notation guarantees.
@@ -75,7 +84,8 @@ from scriptconv import (
75
84
  xsampa_to_ipa, ipa_to_xsampa,
76
85
  buckwalter_to_arabic, arabic_to_buckwalter,
77
86
  lexique_to_ipa, ipa_to_lexique,
78
- kirshenbaum_to_ipa, ipa_to_kirshenbaum, cotovia_to_ipa, ipa_to_cotovia, looks_like_ipa,
87
+ kirshenbaum_to_ipa, ipa_to_kirshenbaum, cotovia_to_ipa, ipa_to_cotovia,
88
+ rfe_to_ipa, ipa_to_rfe, looks_like_ipa,
79
89
  decompose_hangul, hira_to_kana, kana_to_hira,
80
90
  convert, can_convert, convert_batch, Notation, NOTATION_INFO,
81
91
  )
@@ -110,6 +120,9 @@ ipa_to_kirshenbaum("ŋ") # "N"
110
120
  cotovia_to_ipa("karro") # "karo" (Galician Cotovía TTS notation)
111
121
  ipa_to_cotovia("ʎ") # "L"
112
122
 
123
+ rfe_to_ipa("kaša") # "kaʃa" (Spanish/Romance RFE alphabet)
124
+ ipa_to_rfe("ɲ") # "ñ"
125
+
113
126
  looks_like_ipa("pʰɑtʃ") # True (heuristic: has IPA-distinctive symbols)
114
127
  looks_like_ipa("hello") # False
115
128
 
@@ -142,7 +155,7 @@ python -m scriptconv lang ko
142
155
  | Module | Contents |
143
156
  |--------|----------|
144
157
  | `scriptconv.scripts` | `Script` dataclass (with `script_type`), `SCRIPT_REGISTRY` (34 scripts), `detect_script`, `char_script`, `script_distribution`, `script_runs`, `base_direction`, `lang_to_script`, `script_to_langs`, `normalize_script_tag` |
145
- | `scriptconv.notation` | `Notation` enum, `NotationInfo`/`NOTATION_INFO` fidelity registry, `convert` facade, `can_convert` predicate, `convert_batch` generator, pair-wise converters (ARPABET ↔ IPA, X-SAMPA ↔ IPA, Buckwalter ↔ Arabic, Lexique ↔ IPA, Kirshenbaum ↔ IPA, Cotovía ↔ IPA), `looks_like_ipa` detector |
158
+ | `scriptconv.notation` | `Notation` enum, `NotationInfo`/`NOTATION_INFO` fidelity registry, `convert` facade, `can_convert` predicate, `convert_batch` generator, pair-wise converters (ARPABET ↔ IPA, X-SAMPA ↔ IPA, Buckwalter ↔ Arabic, Lexique ↔ IPA, Kirshenbaum ↔ IPA, Cotovía ↔ IPA, RFE ↔ IPA), `looks_like_ipa` detector |
146
159
  | `scriptconv.translit` | `decompose_hangul` (Hangul blocks → jamo, compatibility or conjoining), `hira_to_kana`/`kana_to_hira` — all orthographic only |
147
160
 
148
161
  ## Documentation
@@ -172,6 +185,7 @@ Runnable scripts in [examples/](examples/):
172
185
  | `13_script_runs.py` | Per-script segmentation of mixed-script text |
173
186
  | `14_kana_transliteration.py` | Hiragana ↔ Katakana |
174
187
  | `15_cotovia.py` | Cotovía (Galician TTS notation) ↔ IPA |
188
+ | `16_rfe.py` | RFE (Spanish/Romance philology alphabet) ↔ IPA |
175
189
 
176
190
  ## Fidelity guarantees
177
191
 
@@ -187,6 +201,7 @@ round-trip is exact and what happens to a symbol the table does not know.
187
201
  | **Lexique ↔ IPA** | Exact except the `°`/`3` schwa pair (both → `ə`; reverse always → `°`) | Exact | Passed through unchanged |
188
202
  | **Kirshenbaum ↔ IPA** | Exact | **Lossy** — restricted ASCII inventory; IPA outside it passes through | Passed through unchanged |
189
203
  | **Cotovía ↔ IPA** | Exact except the three `L`/`Z`/`jj` symbols for `ʎ` normalise to `L` | **Lossy** — Galician/Spanish inventory; IPA outside it passes through | Passed through unchanged |
204
+ | **RFE ↔ IPA** | Exact except `ñ`/`n̮` for `ɲ` normalise to `ñ` | **Lossy** — core Spanish/Romance inventory; IPA outside it passes through | Passed through unchanged |
190
205
 
191
206
  This table is also available programmatically via `NOTATION_INFO`
192
207
  (`NotationInfo` records with `lossless_to_ipa`, `lossless_from_ipa`,
@@ -213,4 +228,5 @@ Derived tables used internally:
213
228
  | Lexique phoneme codes | New, B. & Pallier, C. — *Manuel de Lexique 3* v3.11, Tableau 2; [chrplr/openlexicon](https://github.com/chrplr/openlexicon) | CC BY-SA 4.0 |
214
229
  | Kirshenbaum ↔ IPA | Kirshenbaum 1993 ASCII-IPA standard (comp.speech), cross-checked against espeak-ng | — (factual symbol mapping) |
215
230
  | Cotovía ↔ IPA | Universidade de Vigo GTM Cotovía TTS project (`fonemas.cpp`) | — (factual symbol mapping) |
231
+ | RFE ↔ IPA | RFE phonetic alphabet (Revista de Filología Española, 1915) | — (factual symbol mapping) |
216
232
  | Hangul jamo tables | [stannam/hangul_to_ipa](https://github.com/stannam/hangul_to_ipa) | — |
@@ -111,3 +111,9 @@ def test_15_cotovia():
111
111
  r = _run(EXAMPLES_DIR / "15_cotovia.py")
112
112
  assert r.returncode == 0, r.stderr
113
113
  assert r.stdout.strip()
114
+
115
+
116
+ def test_16_rfe():
117
+ r = _run(EXAMPLES_DIR / "16_rfe.py")
118
+ assert r.returncode == 0, r.stderr
119
+ assert r.stdout.strip()
@@ -947,7 +947,7 @@ def test_notation_enum_values():
947
947
 
948
948
 
949
949
  def test_notation_enum_count():
950
- assert len(Notation) == 8
950
+ assert len(Notation) == 9
951
951
 
952
952
 
953
953
  def test_notation_str():
@@ -1108,3 +1108,43 @@ def test_cotovia_pause_marker_not_a_phoneme():
1108
1108
  assert cotovia_to_ipa("#") == "#"
1109
1109
  # p/a/u are ordinary phonemes, converted independently.
1110
1110
  assert cotovia_to_ipa("pau") == "pau"
1111
+
1112
+
1113
+ # ---------------------------------------------------------------------------
1114
+ # RFE (Revista de Filología Española) ↔ IPA
1115
+ # ---------------------------------------------------------------------------
1116
+
1117
+ from scriptconv.notation import rfe_to_ipa, ipa_to_rfe # noqa: E402
1118
+
1119
+
1120
+ @pytest.mark.parametrize("rfe, ipa", [
1121
+ ("š", "ʃ"), ("ž", "ʒ"), ("ĉ", "tʃ"), ("y", "ʝ"), ("ŷ", "ɟʝ"),
1122
+ ("ñ", "ɲ"), ("n̮", "ɲ"), ("l̮", "ʎ"),
1123
+ ("ƀ", "β"), ("đ", "ð"), ("ǥ", "ɣ"), ("θ", "θ"), ("ł", "ɫ"),
1124
+ ("r", "ɾ"), ("r̄", "r"),
1125
+ ("g", "ɡ"),
1126
+ ("kaša", "kaʃa"),
1127
+ ])
1128
+ def test_rfe_to_ipa(rfe, ipa):
1129
+ assert rfe_to_ipa(rfe) == ipa
1130
+
1131
+
1132
+ @pytest.mark.parametrize("ipa, rfe", [
1133
+ ("ʃ", "š"), ("ʒ", "ž"), ("tʃ", "ĉ"), ("ʝ", "y"),
1134
+ ("ɲ", "ñ"), # canonical, not the n̮ variant
1135
+ ("ʎ", "l̮"),
1136
+ ("β", "ƀ"), ("ð", "đ"), ("ɣ", "ǥ"),
1137
+ ("ɾ", "r"), ("r", "r̄"),
1138
+ ])
1139
+ def test_ipa_to_rfe(ipa, rfe):
1140
+ assert ipa_to_rfe(ipa) == rfe
1141
+
1142
+
1143
+ def test_rfe_tap_trill_round_trip():
1144
+ assert ipa_to_rfe(rfe_to_ipa("far̄a")) == "far̄a" # trill
1145
+ assert ipa_to_rfe(rfe_to_ipa("kara")) == "kara" # tap
1146
+
1147
+
1148
+ def test_convert_routes_through_rfe():
1149
+ assert convert("š", "rfe", "x-sampa") == "S"
1150
+ assert convert("ʃ", "ipa", "rfe") == "š"
File without changes
File without changes