msx-charset 0.1.0__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.
- msx_charset-0.1.0/LICENSE +21 -0
- msx_charset-0.1.0/MANIFEST.in +34 -0
- msx_charset-0.1.0/PKG-INFO +117 -0
- msx_charset-0.1.0/README.md +93 -0
- msx_charset-0.1.0/msx_charset/__init__.py +21 -0
- msx_charset-0.1.0/msx_charset/codec_base.py +60 -0
- msx_charset-0.1.0/msx_charset/codec_br.py +84 -0
- msx_charset-0.1.0/msx_charset/codec_intl.py +85 -0
- msx_charset-0.1.0/msx_charset/codec_jp.py +144 -0
- msx_charset-0.1.0/msx_charset/tests/__init__.py +1 -0
- msx_charset-0.1.0/msx_charset/tests/test_charset_br.py +70 -0
- msx_charset-0.1.0/msx_charset/tests/test_charset_intl.py +77 -0
- msx_charset-0.1.0/msx_charset/tests/test_charset_jp.py +109 -0
- msx_charset-0.1.0/msx_charset.egg-info/SOURCES.txt +14 -0
- msx_charset-0.1.0/pyproject.toml +37 -0
- msx_charset-0.1.0/setup.cfg +4 -0
- msx_charset-0.1.0/setup.py +24 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Your Name
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# MANIFEST.in
|
|
2
|
+
include LICENSE
|
|
3
|
+
|
|
4
|
+
# Include README
|
|
5
|
+
include README.md
|
|
6
|
+
|
|
7
|
+
# Include all Python files
|
|
8
|
+
include msx_charset/*.py
|
|
9
|
+
include msx_charset/tests/*.py
|
|
10
|
+
|
|
11
|
+
# Include test data if any
|
|
12
|
+
include msx_charset/tests/data/*
|
|
13
|
+
|
|
14
|
+
# Include documentation
|
|
15
|
+
include docs/*.md
|
|
16
|
+
include docs/*.rst
|
|
17
|
+
|
|
18
|
+
# Include type hints
|
|
19
|
+
include msx_charset/py.typed
|
|
20
|
+
|
|
21
|
+
# Exclude unnecessary files
|
|
22
|
+
exclude .git*
|
|
23
|
+
exclude .github/*
|
|
24
|
+
exclude .vscode/*
|
|
25
|
+
exclude __pycache__/*
|
|
26
|
+
exclude *.pyc
|
|
27
|
+
exclude *.pyo
|
|
28
|
+
exclude *.pyd
|
|
29
|
+
exclude .coverage
|
|
30
|
+
exclude .pytest_cache/*
|
|
31
|
+
exclude .tox/*
|
|
32
|
+
exclude build/*
|
|
33
|
+
exclude dist/*
|
|
34
|
+
exclude *.egg-info/*
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: msx-charset
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MSX character set codecs for Python
|
|
5
|
+
Home-page: https://github.com/yamamo-to/msx-charset
|
|
6
|
+
Author: yamamo-to
|
|
7
|
+
Author-email: yamamo-to <humorum@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Project-URL: Repository, https://github.com/yamamo-to/msx-charset
|
|
10
|
+
Project-URL: Issue, https://github.com/yamamo-to/msx-charset/issues
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Dynamic: author
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: requires-python
|
|
24
|
+
|
|
25
|
+
# MSX Character Set Converter
|
|
26
|
+
|
|
27
|
+
[](https://github.com/yamamo-to/msx-charset/actions/workflows/test.yml)
|
|
28
|
+
|
|
29
|
+
A Python package for converting between Unicode and MSX character sets, supporting Japanese, International, and Brazilian character sets.
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- Support for MSX character set conversion:
|
|
34
|
+
- Japanese version
|
|
35
|
+
- International version
|
|
36
|
+
- Brazilian version
|
|
37
|
+
- Compatible with Python 3.8 and later
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install msx-charset
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### Japanese Character Set
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
import msx_charset
|
|
51
|
+
|
|
52
|
+
# Encoding
|
|
53
|
+
text = "こんにちは"
|
|
54
|
+
encoded = text.encode('msx-jp')
|
|
55
|
+
print(encoded) # MSX code byte sequence
|
|
56
|
+
|
|
57
|
+
# Decoding
|
|
58
|
+
decoded = encoded.decode('msx-jp')
|
|
59
|
+
print(decoded) # "こんにちは"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### International Character Set
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import msx_charset
|
|
66
|
+
|
|
67
|
+
# Encoding
|
|
68
|
+
text = "áéíóú"
|
|
69
|
+
encoded = text.encode('msx-intl')
|
|
70
|
+
print(encoded) # MSX code byte sequence
|
|
71
|
+
|
|
72
|
+
# Decoding
|
|
73
|
+
decoded = encoded.decode('msx-intl')
|
|
74
|
+
print(decoded) # "áéíóú"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Brazilian Character Set
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import msx_charset
|
|
81
|
+
|
|
82
|
+
# Encoding
|
|
83
|
+
text = "Olá, mundo!"
|
|
84
|
+
encoded = text.encode('msx-br')
|
|
85
|
+
print(encoded) # MSX code byte sequence
|
|
86
|
+
|
|
87
|
+
# Decoding
|
|
88
|
+
decoded = encoded.decode('msx-br')
|
|
89
|
+
print(decoded) # "Olá, mundo!"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Development
|
|
93
|
+
|
|
94
|
+
### Setup
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Create virtual environment
|
|
98
|
+
python -m venv venv
|
|
99
|
+
source venv/bin/activate # Windows: venv\Scripts\activate
|
|
100
|
+
|
|
101
|
+
# Install development package
|
|
102
|
+
pip install -e .
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Running Tests
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
python -m unittest discover -s msx_charset/tests
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Contributing
|
|
112
|
+
|
|
113
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
MIT License
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# MSX Character Set Converter
|
|
2
|
+
|
|
3
|
+
[](https://github.com/yamamo-to/msx-charset/actions/workflows/test.yml)
|
|
4
|
+
|
|
5
|
+
A Python package for converting between Unicode and MSX character sets, supporting Japanese, International, and Brazilian character sets.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Support for MSX character set conversion:
|
|
10
|
+
- Japanese version
|
|
11
|
+
- International version
|
|
12
|
+
- Brazilian version
|
|
13
|
+
- Compatible with Python 3.8 and later
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install msx-charset
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Japanese Character Set
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import msx_charset
|
|
27
|
+
|
|
28
|
+
# Encoding
|
|
29
|
+
text = "こんにちは"
|
|
30
|
+
encoded = text.encode('msx-jp')
|
|
31
|
+
print(encoded) # MSX code byte sequence
|
|
32
|
+
|
|
33
|
+
# Decoding
|
|
34
|
+
decoded = encoded.decode('msx-jp')
|
|
35
|
+
print(decoded) # "こんにちは"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### International Character Set
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import msx_charset
|
|
42
|
+
|
|
43
|
+
# Encoding
|
|
44
|
+
text = "áéíóú"
|
|
45
|
+
encoded = text.encode('msx-intl')
|
|
46
|
+
print(encoded) # MSX code byte sequence
|
|
47
|
+
|
|
48
|
+
# Decoding
|
|
49
|
+
decoded = encoded.decode('msx-intl')
|
|
50
|
+
print(decoded) # "áéíóú"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Brazilian Character Set
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
import msx_charset
|
|
57
|
+
|
|
58
|
+
# Encoding
|
|
59
|
+
text = "Olá, mundo!"
|
|
60
|
+
encoded = text.encode('msx-br')
|
|
61
|
+
print(encoded) # MSX code byte sequence
|
|
62
|
+
|
|
63
|
+
# Decoding
|
|
64
|
+
decoded = encoded.decode('msx-br')
|
|
65
|
+
print(decoded) # "Olá, mundo!"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Development
|
|
69
|
+
|
|
70
|
+
### Setup
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Create virtual environment
|
|
74
|
+
python -m venv venv
|
|
75
|
+
source venv/bin/activate # Windows: venv\Scripts\activate
|
|
76
|
+
|
|
77
|
+
# Install development package
|
|
78
|
+
pip install -e .
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Running Tests
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
python -m unittest discover -s msx_charset/tests
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Contributing
|
|
88
|
+
|
|
89
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
MIT License
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import codecs
|
|
2
|
+
from .codec_jp import msx_codec_jp
|
|
3
|
+
from .codec_intl import msx_codec_intl
|
|
4
|
+
from .codec_br import msx_codec_br
|
|
5
|
+
|
|
6
|
+
__version__ = "0.1.0"
|
|
7
|
+
__all__ = ["msx_codec_jp", "msx_codec_intl", "msx_codec_br"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def msx_charset(name):
|
|
11
|
+
if name.lower() in ('msx-jp', 'msx_jp'):
|
|
12
|
+
return msx_codec_jp
|
|
13
|
+
elif name.lower() in ('msx-intl', 'msx_intl'):
|
|
14
|
+
return msx_codec_intl
|
|
15
|
+
elif name.lower() in ('msx-br', 'msx_br'):
|
|
16
|
+
return msx_codec_br
|
|
17
|
+
raise LookupError(f"unknown encoding: {name}")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Register codec
|
|
21
|
+
codecs.register(msx_charset)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import codecs
|
|
2
|
+
|
|
3
|
+
class MSXCodecBase:
|
|
4
|
+
"""Base class for MSX character set codecs"""
|
|
5
|
+
|
|
6
|
+
def __init__(self, name, custom_map, graphic_map):
|
|
7
|
+
self.name = name
|
|
8
|
+
|
|
9
|
+
# ASCII (0x00-0x7F) range mapping
|
|
10
|
+
self.ascii_map = {
|
|
11
|
+
i: chr(i) for i in range(0x80)
|
|
12
|
+
if chr(i).isprintable() or chr(i) in '\x00\x07\x08\x09\x0A\x0D\x1B\x20'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
# Character mappings
|
|
16
|
+
self.char_map = {**self.ascii_map, **custom_map}
|
|
17
|
+
self.char_reverse_map = {v: k for k, v in self.char_map.items()}
|
|
18
|
+
self.graphic_map = graphic_map
|
|
19
|
+
self.graphic_reverse_map = {v: k for k, v in graphic_map.items()}
|
|
20
|
+
|
|
21
|
+
# Create codec info
|
|
22
|
+
self.codec_info = codecs.CodecInfo(
|
|
23
|
+
name=name,
|
|
24
|
+
encode=self.encode,
|
|
25
|
+
decode=self.decode
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
def encode(self, text, errors='strict'):
|
|
29
|
+
"""Convert UTF-8 string to MSX code byte sequence"""
|
|
30
|
+
result = bytearray()
|
|
31
|
+
for char in text:
|
|
32
|
+
if char in self.graphic_map:
|
|
33
|
+
result.extend(self.graphic_map[char])
|
|
34
|
+
else:
|
|
35
|
+
result.append(self.char_reverse_map.get(char, 0x3F))
|
|
36
|
+
return bytes(result), len(text)
|
|
37
|
+
|
|
38
|
+
def decode(self, codes, errors='strict'):
|
|
39
|
+
"""Convert MSX code byte sequence to UTF-8 string"""
|
|
40
|
+
result = []
|
|
41
|
+
i = 0
|
|
42
|
+
codes_len = len(codes)
|
|
43
|
+
|
|
44
|
+
while i < codes_len:
|
|
45
|
+
code = codes[i]
|
|
46
|
+
|
|
47
|
+
# Handle graphic characters
|
|
48
|
+
if code == 0x01 and i + 1 < codes_len:
|
|
49
|
+
next_code = codes[i + 1]
|
|
50
|
+
char = self.graphic_reverse_map.get((code, next_code))
|
|
51
|
+
if char:
|
|
52
|
+
result.append(char)
|
|
53
|
+
i += 2
|
|
54
|
+
continue
|
|
55
|
+
|
|
56
|
+
# Handle regular characters
|
|
57
|
+
result.append(self.char_map.get(code, '?'))
|
|
58
|
+
i += 1
|
|
59
|
+
|
|
60
|
+
return ''.join(result), len(codes)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import codecs
|
|
2
|
+
from .codec_base import MSXCodecBase
|
|
3
|
+
|
|
4
|
+
# Define data first
|
|
5
|
+
# ASCII (0x00-0x7F) range mapping (some control characters are allowed)
|
|
6
|
+
MSX_ASCII_MAP = {
|
|
7
|
+
i: chr(i) for i in range(0x80)
|
|
8
|
+
if chr(i).isprintable() or chr(i) in '\x00\x07\x08\x09\x0A\x0D\x1B\x20'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
# MSX Brazilian
|
|
12
|
+
MSX_CUSTOM_MAP_BR = {
|
|
13
|
+
0x80: 'Ç', 0x81: 'ü', 0x82: 'é', 0x83: 'â',
|
|
14
|
+
0x84: 'Á', 0x85: 'à', 0x86: '¨', 0x87: 'ç',
|
|
15
|
+
0x88: 'ê', 0x89: 'Í', 0x8A: 'Ó', 0x8B: 'Ú',
|
|
16
|
+
0x8C: 'Â', 0x8D: 'Ê', 0x8E: 'Ô', 0x8F: 'À',
|
|
17
|
+
0x90: 'É', 0x91: 'æ', 0x92: 'Æ', 0x93: 'ô',
|
|
18
|
+
0x94: 'ö', 0x95: 'ò', 0x96: 'û', 0x97: 'ù',
|
|
19
|
+
0x98: 'ÿ', 0x99: 'Ö', 0x9A: 'Ü', 0x9B: '¢',
|
|
20
|
+
0x9C: '£', 0x9D: '¥', 0x9E: 'Cz', 0x9F: 'ƒ',
|
|
21
|
+
|
|
22
|
+
0xA0: 'á', 0xA1: 'í', 0xA2: 'ó', 0xA3: 'ú',
|
|
23
|
+
0xA4: 'ñ', 0xA5: 'Ñ', 0xA6: 'ª', 0xA7: 'º',
|
|
24
|
+
0xA8: '¿', 0xA9: '⌐', 0xAA: '¬', 0xAB: '½',
|
|
25
|
+
0xAC: '¼', 0xAD: '¡', 0xAE: '«', 0xAF: '»',
|
|
26
|
+
0xB0: 'Ã', 0xB1: 'ã', 0xB2: 'Ĩ', 0xB3: 'ĩ',
|
|
27
|
+
0xB4: 'Õ', 0xB5: 'õ', 0xB6: 'Ű', 0xB7: 'ű',
|
|
28
|
+
0xB8: 'IJ', 0xB9: 'ij', 0xBA: '¾', 0xBB: '∽',
|
|
29
|
+
0xBC: '◊', 0xBD: '‰', 0xBE: '¶', 0xBF: '§',
|
|
30
|
+
|
|
31
|
+
0xC0: '▂', 0xC1: '▚', 0xC2: '▆', 0xC3: '🮂',
|
|
32
|
+
0xC4: '▬', 0xC5: '🮅', 0xC6: '▎', 0xC7: '▞',
|
|
33
|
+
0xC8: '▊', 0xC9: '🮇', 0xCA: '🮊', 0xCB: '🮙',
|
|
34
|
+
0xCC: '🮘', 0xCD: '🭭', 0xCE: '🭯', 0xCF: '🭬',
|
|
35
|
+
0xD0: '🭮', 0xD1: '🮚', 0xD2: '🮛', 0xD3: '▘',
|
|
36
|
+
0xD4: '▗', 0xD5: '▝', 0xD6: '▖', 0xD7: '🮖',
|
|
37
|
+
0xD8: 'Δ', 0xD9: '‡', 0xDA: 'ω', 0xDB: '█',
|
|
38
|
+
0xDC: '▄', 0xDD: '▌', 0xDE: '▐', 0xDF: '▀',
|
|
39
|
+
|
|
40
|
+
0xE0: 'α', 0xE1: 'ß', 0xE2: 'Γ', 0xE3: 'π',
|
|
41
|
+
0xE4: 'Σ', 0xE5: 'σ', 0xE6: 'µ', 0xE7: 'τ',
|
|
42
|
+
0xE8: 'Φ', 0xE9: 'Θ', 0xEA: 'Ω', 0xEB: 'δ',
|
|
43
|
+
0xEC: '∞', 0xED: '⌀', 0xEE: '∈', 0xEF: '∩',
|
|
44
|
+
0xF0: '≡', 0xF1: '±', 0xF2: '≥', 0xF3: '≤',
|
|
45
|
+
0xF4: '⌠', 0xF5: '⌡', 0xF6: '÷', 0xF7: '≈',
|
|
46
|
+
0xF8: '°', 0xF9: '∙', 0xFA: '·', 0xFB: '√',
|
|
47
|
+
0xFC: 'ⁿ', 0xFD: '²', 0xFE: '■'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Combined map (MSX code to character)
|
|
51
|
+
MSX_CHAR_MAP_BR = dict(MSX_ASCII_MAP)
|
|
52
|
+
MSX_CHAR_MAP_BR.update(MSX_CUSTOM_MAP_BR)
|
|
53
|
+
|
|
54
|
+
# Reverse lookup (character to MSX code)
|
|
55
|
+
MSX_CHAR_REVERSE_MAP_BR = {v: k for k, v in MSX_CHAR_MAP_BR.items()}
|
|
56
|
+
|
|
57
|
+
# Graphic character mapping (2-byte characters)
|
|
58
|
+
GRAPHIC_CHAR_MAP_BR = {
|
|
59
|
+
'☺': (0x01, 0x41), '☻': (0x01, 0x42), '♥': (0x01, 0x43),
|
|
60
|
+
'♦': (0x01, 0x44), '♣': (0x01, 0x45), '♠': (0x01, 0x46),
|
|
61
|
+
'•': (0x01, 0x47), '◘': (0x01, 0x48), '○': (0x01, 0x49),
|
|
62
|
+
'◙': (0x01, 0x4A), '♂': (0x01, 0x4B), '♀': (0x01, 0x4C),
|
|
63
|
+
'♪': (0x01, 0x4D), '♫': (0x01, 0x4E), '☼': (0x01, 0x4F),
|
|
64
|
+
'⟊': (0x01, 0x50), '┴': (0x01, 0x51), '┬': (0x01, 0x52),
|
|
65
|
+
'┤': (0x01, 0x53), '├': (0x01, 0x54), '┼': (0x01, 0x55),
|
|
66
|
+
'│': (0x01, 0x56), '─': (0x01, 0x57), '┌': (0x01, 0x58),
|
|
67
|
+
'┐': (0x01, 0x59), '└': (0x01, 0x5A), '┘': (0x01, 0x5B),
|
|
68
|
+
'╳': (0x01, 0x5C), '╱': (0x01, 0x5D), '╲': (0x01, 0x5E),
|
|
69
|
+
'🮯': (0x01, 0x5F)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Reverse lookup for graphic characters
|
|
73
|
+
GRAPHIC_CHAR_REVERSE_MAP_BR = {v: k for k, v in GRAPHIC_CHAR_MAP_BR.items()}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class MSXBrazilianCodec(MSXCodecBase):
|
|
77
|
+
"""Brazilian MSX character set codec"""
|
|
78
|
+
|
|
79
|
+
def __init__(self):
|
|
80
|
+
super().__init__('msx-br', MSX_CUSTOM_MAP_BR, GRAPHIC_CHAR_MAP_BR)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Create codec instance
|
|
84
|
+
msx_codec_br = MSXBrazilianCodec().codec_info
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import codecs
|
|
2
|
+
from .codec_base import MSXCodecBase
|
|
3
|
+
|
|
4
|
+
# Define data first
|
|
5
|
+
# ASCII (0x00-0x7F) range mapping (some control characters are allowed)
|
|
6
|
+
MSX_ASCII_MAP = {
|
|
7
|
+
i: chr(i) for i in range(0x80)
|
|
8
|
+
if chr(i).isprintable() or chr(i) in '\x00\x07\x08\x09\x0A\x0D\x1B\x20'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
# MSX International
|
|
12
|
+
MSX_CUSTOM_MAP_INTL = {
|
|
13
|
+
0x80: 'Ç', 0x81: 'ü', 0x82: 'é', 0x83: 'â',
|
|
14
|
+
0x84: 'ä', 0x85: 'à', 0x86: 'å', 0x87: 'ç',
|
|
15
|
+
0x88: 'ê', 0x89: 'ë', 0x8A: 'è', 0x8B: 'ï',
|
|
16
|
+
0x8C: 'î', 0x8D: 'ì', 0x8E: 'Ä', 0x8F: 'Å',
|
|
17
|
+
0x90: 'É', 0x91: 'æ', 0x92: 'Æ', 0x93: 'ô',
|
|
18
|
+
0x94: 'ö', 0x95: 'ò', 0x96: 'û', 0x97: 'ù',
|
|
19
|
+
0x98: 'ÿ', 0x99: 'Ö', 0x9A: 'Ü', 0x9B: '¢',
|
|
20
|
+
0x9C: '£', 0x9D: '¥', 0x9E: '₧', 0x9F: 'ƒ',
|
|
21
|
+
|
|
22
|
+
0xA0: 'á', 0xA1: 'í', 0xA2: 'ó', 0xA3: 'ú',
|
|
23
|
+
0xA4: 'ñ', 0xA5: 'Ñ', 0xA6: 'ª', 0xA7: 'º',
|
|
24
|
+
0xA8: '¿', 0xA9: '⌐', 0xAA: '¬', 0xAB: '½',
|
|
25
|
+
0xAC: '¼', 0xAD: '¡', 0xAE: '«', 0xAF: '»',
|
|
26
|
+
0xB0: 'Ã', 0xB1: 'ã', 0xB2: 'Ĩ', 0xB3: 'ĩ',
|
|
27
|
+
0xB4: 'Õ', 0xB5: 'õ', 0xB6: 'Ű', 0xB7: 'ű',
|
|
28
|
+
0xB8: 'IJ', 0xB9: 'ij', 0xBA: '¾', 0xBB: '∽',
|
|
29
|
+
0xBC: '◊', 0xBD: '‰', 0xBE: '¶', 0xBF: '§',
|
|
30
|
+
|
|
31
|
+
0xC0: '▂', 0xC1: '▚', 0xC2: '▆', 0xC3: '🮂',
|
|
32
|
+
0xC4: '▬', 0xC5: '🮅', 0xC6: '▎', 0xC7: '▞',
|
|
33
|
+
0xC8: '▊', 0xC9: '🮇', 0xCA: '🮊', 0xCB: '🮙',
|
|
34
|
+
0xCC: '🮘', 0xCD: '🭭', 0xCE: '🭯', 0xCF: '🭬',
|
|
35
|
+
0xD0: '🭮', 0xD1: '🮚', 0xD2: '🮛', 0xD3: '▘',
|
|
36
|
+
0xD4: '▗', 0xD5: '▝', 0xD6: '▖', 0xD7: '🮖',
|
|
37
|
+
0xD8: 'Δ', 0xD9: '‡', 0xDA: 'ω', 0xDB: '█',
|
|
38
|
+
0xDC: '▄', 0xDD: '▌', 0xDE: '▐', 0xDF: '▀',
|
|
39
|
+
|
|
40
|
+
0xE0: 'α', 0xE1: 'ß', 0xE2: 'Γ', 0xE3: 'π',
|
|
41
|
+
0xE4: 'Σ', 0xE5: 'σ', 0xE6: 'µ', 0xE7: 'τ',
|
|
42
|
+
0xE8: 'Φ', 0xE9: 'Θ', 0xEA: 'Ω', 0xEB: 'δ',
|
|
43
|
+
0xEC: '∞', 0xED: '⌀', 0xEE: '∈', 0xEF: '∩',
|
|
44
|
+
0xF0: '≡', 0xF1: '±', 0xF2: '≥', 0xF3: '≤',
|
|
45
|
+
0xF4: '⌠', 0xF5: '⌡', 0xF6: '÷', 0xF7: '≈',
|
|
46
|
+
0xF8: '°', 0xF9: '∙', 0xFA: '·', 0xFB: '√',
|
|
47
|
+
0xFC: 'ⁿ', 0xFD: '²', 0xFE: '■'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Combined map (MSX code to character)
|
|
51
|
+
MSX_CHAR_MAP_INTL = dict(MSX_ASCII_MAP)
|
|
52
|
+
MSX_CHAR_MAP_INTL.update(MSX_CUSTOM_MAP_INTL)
|
|
53
|
+
|
|
54
|
+
# Reverse lookup (character to MSX code)
|
|
55
|
+
MSX_CHAR_REVERSE_MAP_INTL = {v: k for k, v in MSX_CHAR_MAP_INTL.items()}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Graphic character mapping (2-byte characters)
|
|
59
|
+
GRAPHIC_CHAR_MAP_INTL = {
|
|
60
|
+
'☺': (0x01, 0x41), '☻': (0x01, 0x42), '♥': (0x01, 0x43),
|
|
61
|
+
'♦': (0x01, 0x44), '♣': (0x01, 0x45), '♠': (0x01, 0x46),
|
|
62
|
+
'•': (0x01, 0x47), '◘': (0x01, 0x48), '○': (0x01, 0x49),
|
|
63
|
+
'◙': (0x01, 0x4A), '♂': (0x01, 0x4B), '♀': (0x01, 0x4C),
|
|
64
|
+
'♪': (0x01, 0x4D), '♫': (0x01, 0x4E), '☼': (0x01, 0x4F),
|
|
65
|
+
'⟊': (0x01, 0x50), '┴': (0x01, 0x51), '┬': (0x01, 0x52),
|
|
66
|
+
'┤': (0x01, 0x53), '├': (0x01, 0x54), '┼': (0x01, 0x55),
|
|
67
|
+
'│': (0x01, 0x56), '─': (0x01, 0x57), '┌': (0x01, 0x58),
|
|
68
|
+
'┐': (0x01, 0x59), '└': (0x01, 0x5A), '┘': (0x01, 0x5B),
|
|
69
|
+
'╳': (0x01, 0x5C), '╱': (0x01, 0x5D), '╲': (0x01, 0x5E),
|
|
70
|
+
'🮯': (0x01, 0x5F)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Reverse lookup for graphic characters
|
|
74
|
+
GRAPHIC_CHAR_REVERSE_MAP_INTL = {v: k for k, v in GRAPHIC_CHAR_MAP_INTL.items()}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class MSXInternationalCodec(MSXCodecBase):
|
|
78
|
+
"""International MSX character set codec"""
|
|
79
|
+
|
|
80
|
+
def __init__(self):
|
|
81
|
+
super().__init__('msx-intl', MSX_CUSTOM_MAP_INTL, GRAPHIC_CHAR_MAP_INTL)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# Create codec instance
|
|
85
|
+
msx_codec_intl = MSXInternationalCodec().codec_info
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from .codec_base import MSXCodecBase
|
|
2
|
+
|
|
3
|
+
# MSX-specific Japanese and symbol characters (0x80-0xFE)
|
|
4
|
+
MSX_CUSTOM_MAP_JP = {
|
|
5
|
+
# Column 1 (0x80-0x9F): Special characters and hiragana
|
|
6
|
+
0x80: '♠', 0x81: '♥', 0x82: '♣', 0x83: '♦',
|
|
7
|
+
0x84: '○', 0x85: '●', 0x86: 'を', 0x87: 'ぁ',
|
|
8
|
+
0x88: 'ぃ', 0x89: 'ぅ', 0x8A: 'ぇ', 0x8B: 'ぉ',
|
|
9
|
+
0x8C: 'ゃ', 0x8D: 'ゅ', 0x8E: 'ょ', 0x8F: 'っ',
|
|
10
|
+
0x90: ' ', 0x91: 'あ', 0x92: 'い', 0x93: 'う',
|
|
11
|
+
0x94: 'え', 0x95: 'お', 0x96: 'か', 0x97: 'き',
|
|
12
|
+
0x98: 'く', 0x99: 'け', 0x9A: 'こ', 0x9B: 'さ',
|
|
13
|
+
0x9C: 'し', 0x9D: 'す', 0x9E: 'せ', 0x9F: 'そ',
|
|
14
|
+
|
|
15
|
+
# Column 2 (0xA0-0xBF): Symbols and katakana
|
|
16
|
+
0xA0: ' ', 0xA1: '。', 0xA2: '「', 0xA3: '」',
|
|
17
|
+
0xA4: '、', 0xA5: '・', 0xA6: 'ヲ', 0xA7: 'ァ',
|
|
18
|
+
0xA8: 'ィ', 0xA9: 'ゥ', 0xAA: 'ェ', 0xAB: 'ォ',
|
|
19
|
+
0xAC: 'ャ', 0xAD: 'ュ', 0xAE: 'ョ', 0xAF: 'ッ',
|
|
20
|
+
0xB0: 'ー', 0xB1: 'ア', 0xB2: 'イ', 0xB3: 'ウ',
|
|
21
|
+
0xB4: 'エ', 0xB5: 'オ', 0xB6: 'カ', 0xB7: 'キ',
|
|
22
|
+
0xB8: 'ク', 0xB9: 'ケ', 0xBA: 'コ', 0xBB: 'サ',
|
|
23
|
+
0xBC: 'シ', 0xBD: 'ス', 0xBE: 'セ', 0xBF: 'ソ',
|
|
24
|
+
|
|
25
|
+
# Column 3 (0xC0-0xDF): Katakana (continued)
|
|
26
|
+
0xC0: 'タ', 0xC1: 'チ', 0xC2: 'ツ', 0xC3: 'テ',
|
|
27
|
+
0xC4: 'ト', 0xC5: 'ナ', 0xC6: 'ニ', 0xC7: 'ヌ',
|
|
28
|
+
0xC8: 'ネ', 0xC9: 'ノ', 0xCA: 'ハ', 0xCB: 'ヒ',
|
|
29
|
+
0xCC: 'フ', 0xCD: 'ヘ', 0xCE: 'ホ', 0xCF: 'マ',
|
|
30
|
+
0xD0: 'ミ', 0xD1: 'ム', 0xD2: 'メ', 0xD3: 'モ',
|
|
31
|
+
0xD4: 'ヤ', 0xD5: 'ユ', 0xD6: 'ヨ', 0xD7: 'ラ',
|
|
32
|
+
0xD8: 'リ', 0xD9: 'ル', 0xDA: 'レ', 0xDB: 'ロ',
|
|
33
|
+
0xDC: 'ワ', 0xDD: 'ン', 0xDE: '゛', 0xDF: '゜',
|
|
34
|
+
|
|
35
|
+
# Column 4 (0xE0-0xFE): Hiragana (continued)
|
|
36
|
+
0xE0: 'た', 0xE1: 'ち', 0xE2: 'つ', 0xE3: 'て',
|
|
37
|
+
0xE4: 'と', 0xE5: 'な', 0xE6: 'に', 0xE7: 'ぬ',
|
|
38
|
+
0xE8: 'ね', 0xE9: 'の', 0xEA: 'は', 0xEB: 'ひ',
|
|
39
|
+
0xEC: 'ふ', 0xED: 'へ', 0xEE: 'ほ', 0xEF: 'ま',
|
|
40
|
+
0xF0: 'み', 0xF1: 'む', 0xF2: 'め', 0xF3: 'も',
|
|
41
|
+
0xF4: 'や', 0xF5: 'ゆ', 0xF6: 'よ', 0xF7: 'ら',
|
|
42
|
+
0xF8: 'り', 0xF9: 'る', 0xFA: 'れ', 0xFB: 'ろ',
|
|
43
|
+
0xFC: 'わ', 0xFD: 'ん', 0xFE: '!' # Full-width exclamation mark
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Graphic character mapping (2-byte characters)
|
|
47
|
+
GRAPHIC_CHAR_MAP_JP = {
|
|
48
|
+
'月': (0x01, 0x41), '火': (0x01, 0x42), '水': (0x01, 0x43),
|
|
49
|
+
'木': (0x01, 0x44), '金': (0x01, 0x45), '土': (0x01, 0x46),
|
|
50
|
+
'日': (0x01, 0x47), '年': (0x01, 0x48), '円': (0x01, 0x49),
|
|
51
|
+
'時': (0x01, 0x4A), '分': (0x01, 0x4B), '秒': (0x01, 0x4C),
|
|
52
|
+
'百': (0x01, 0x4D), '千': (0x01, 0x4E), '万': (0x01, 0x4F),
|
|
53
|
+
'π': (0x01, 0x50), '┴': (0x01, 0x51), '┬': (0x01, 0x52),
|
|
54
|
+
'┤': (0x01, 0x53), '├': (0x01, 0x54), '┼': (0x01, 0x55),
|
|
55
|
+
'│': (0x01, 0x56), '─': (0x01, 0x57), '┌': (0x01, 0x58),
|
|
56
|
+
'┐': (0x01, 0x59), '└': (0x01, 0x5A), '┘': (0x01, 0x5B),
|
|
57
|
+
'×': (0x01, 0x5C), '大': (0x01, 0x5D), '中': (0x01, 0x5E),
|
|
58
|
+
'小': (0x01, 0x5F)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Voiced sound mark and semi-voiced sound mark mapping
|
|
62
|
+
DAKUTEN_MAP = {
|
|
63
|
+
'が': ('か', 0xDE), 'ぎ': ('き', 0xDE), 'ぐ': ('く', 0xDE),
|
|
64
|
+
'げ': ('け', 0xDE), 'ご': ('こ', 0xDE),
|
|
65
|
+
'ざ': ('さ', 0xDE), 'じ': ('し', 0xDE), 'ず': ('す', 0xDE),
|
|
66
|
+
'ぜ': ('せ', 0xDE), 'ぞ': ('そ', 0xDE),
|
|
67
|
+
'だ': ('た', 0xDE), 'ぢ': ('ち', 0xDE), 'づ': ('つ', 0xDE),
|
|
68
|
+
'で': ('て', 0xDE), 'ど': ('と', 0xDE),
|
|
69
|
+
'ば': ('は', 0xDE), 'び': ('ひ', 0xDE), 'ぶ': ('ふ', 0xDE),
|
|
70
|
+
'べ': ('へ', 0xDE), 'ぼ': ('ほ', 0xDE),
|
|
71
|
+
'ぱ': ('は', 0xDF), 'ぴ': ('ひ', 0xDF), 'ぷ': ('ふ', 0xDF),
|
|
72
|
+
'ぺ': ('へ', 0xDF), 'ぽ': ('ほ', 0xDF),
|
|
73
|
+
'ガ': ('カ', 0xDE), 'ギ': ('キ', 0xDE), 'グ': ('ク', 0xDE),
|
|
74
|
+
'ゲ': ('ケ', 0xDE), 'ゴ': ('コ', 0xDE),
|
|
75
|
+
'ザ': ('サ', 0xDE), 'ジ': ('シ', 0xDE), 'ズ': ('ス', 0xDE),
|
|
76
|
+
'ゼ': ('セ', 0xDE), 'ゾ': ('ソ', 0xDE),
|
|
77
|
+
'ダ': ('タ', 0xDE), 'ヂ': ('チ', 0xDE), 'ヅ': ('ツ', 0xDE),
|
|
78
|
+
'デ': ('テ', 0xDE), 'ド': ('ト', 0xDE),
|
|
79
|
+
'バ': ('ハ', 0xDE), 'ビ': ('ヒ', 0xDE), 'ブ': ('フ', 0xDE),
|
|
80
|
+
'ベ': ('ヘ', 0xDE), 'ボ': ('ホ', 0xDE),
|
|
81
|
+
'パ': ('ハ', 0xDF), 'ピ': ('ヒ', 0xDF), 'プ': ('フ', 0xDF),
|
|
82
|
+
'ペ': ('ヘ', 0xDF), 'ポ': ('ホ', 0xDF)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class MSXJapaneseCodec(MSXCodecBase):
|
|
87
|
+
"""Japanese MSX character set codec"""
|
|
88
|
+
|
|
89
|
+
def __init__(self):
|
|
90
|
+
super().__init__('msx-jp', MSX_CUSTOM_MAP_JP, GRAPHIC_CHAR_MAP_JP)
|
|
91
|
+
self.dakuten_map = DAKUTEN_MAP
|
|
92
|
+
self.dakuten_reverse_map = {(v, m): k for k, (v, m) in DAKUTEN_MAP.items()}
|
|
93
|
+
|
|
94
|
+
def encode(self, text, errors='strict'):
|
|
95
|
+
"""Convert UTF-8 string to MSX code byte sequence (Japanese)"""
|
|
96
|
+
result = bytearray()
|
|
97
|
+
for char in text:
|
|
98
|
+
if char in self.graphic_map:
|
|
99
|
+
result.extend(self.graphic_map[char])
|
|
100
|
+
elif char in self.dakuten_map:
|
|
101
|
+
base, mark = self.dakuten_map[char]
|
|
102
|
+
result.extend([self.char_reverse_map.get(base, 0x3F), mark])
|
|
103
|
+
else:
|
|
104
|
+
result.append(self.char_reverse_map.get(char, 0x3F))
|
|
105
|
+
return bytes(result), len(text)
|
|
106
|
+
|
|
107
|
+
def decode(self, codes, errors='strict'):
|
|
108
|
+
"""Convert MSX code byte sequence to UTF-8 string"""
|
|
109
|
+
result = []
|
|
110
|
+
i = 0
|
|
111
|
+
codes_len = len(codes)
|
|
112
|
+
|
|
113
|
+
while i < codes_len:
|
|
114
|
+
code = codes[i]
|
|
115
|
+
|
|
116
|
+
# Handle graphic characters
|
|
117
|
+
if code == 0x01 and i + 1 < codes_len:
|
|
118
|
+
next_code = codes[i + 1]
|
|
119
|
+
char = self.graphic_reverse_map.get((code, next_code))
|
|
120
|
+
if char:
|
|
121
|
+
result.append(char)
|
|
122
|
+
i += 2
|
|
123
|
+
continue
|
|
124
|
+
|
|
125
|
+
# Handle dakuten/handakuten
|
|
126
|
+
if i + 1 < codes_len and codes[i + 1] in (0xDE, 0xDF):
|
|
127
|
+
base_char = self.char_map.get(code)
|
|
128
|
+
mark = codes[i + 1]
|
|
129
|
+
composed = self.dakuten_reverse_map.get((base_char, mark))
|
|
130
|
+
if composed:
|
|
131
|
+
result.append(composed)
|
|
132
|
+
else:
|
|
133
|
+
mark_char = '゛' if mark == 0xDE else '゜'
|
|
134
|
+
result.append(base_char + mark_char)
|
|
135
|
+
i += 2
|
|
136
|
+
else:
|
|
137
|
+
result.append(self.char_map.get(code, '?'))
|
|
138
|
+
i += 1
|
|
139
|
+
|
|
140
|
+
return ''.join(result), len(codes)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# Create codec instance
|
|
144
|
+
msx_codec_jp = MSXJapaneseCodec().codec_info
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Test package initialization file
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import codecs
|
|
3
|
+
from msx_charset import msx_charset
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestMSXCharsetBR(unittest.TestCase):
|
|
7
|
+
@classmethod
|
|
8
|
+
def setUpClass(cls):
|
|
9
|
+
# テスト実行前に文字セットを登録
|
|
10
|
+
codecs.register(msx_charset)
|
|
11
|
+
|
|
12
|
+
def test_encode_decode_ascii(self):
|
|
13
|
+
text = "Hello, World!"
|
|
14
|
+
encoded = text.encode("msx-br")
|
|
15
|
+
decoded = encoded.decode("msx-br")
|
|
16
|
+
self.assertEqual(text, decoded)
|
|
17
|
+
|
|
18
|
+
def test_encode_decode_accented_chars(self):
|
|
19
|
+
text = "Á¨ÍÓÚÂÊÔÀ"
|
|
20
|
+
encoded = text.encode("msx-br")
|
|
21
|
+
decoded = encoded.decode("msx-br")
|
|
22
|
+
self.assertEqual(text, decoded)
|
|
23
|
+
|
|
24
|
+
def test_encode_decode_graphic_chars(self):
|
|
25
|
+
text = "☺☻♥♦♣♠"
|
|
26
|
+
encoded = text.encode("msx-br")
|
|
27
|
+
decoded = encoded.decode("msx-br")
|
|
28
|
+
self.assertEqual(text, decoded)
|
|
29
|
+
|
|
30
|
+
def test_encode_decode_mixed(self):
|
|
31
|
+
text = "Olá, mundo!"
|
|
32
|
+
encoded = text.encode("msx-br")
|
|
33
|
+
decoded = encoded.decode("msx-br")
|
|
34
|
+
self.assertEqual(text, decoded)
|
|
35
|
+
|
|
36
|
+
def test_codec_registration(self):
|
|
37
|
+
self.assertIsNotNone(codecs.lookup("msx-br"))
|
|
38
|
+
self.assertIsNotNone(codecs.lookup("msx_br"))
|
|
39
|
+
|
|
40
|
+
def test_encode_bytes_ascii(self):
|
|
41
|
+
# ASCII文字のバイト列テスト
|
|
42
|
+
text = "Hello!"
|
|
43
|
+
expected = bytes([0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21])
|
|
44
|
+
encoded = text.encode("msx-br")
|
|
45
|
+
self.assertEqual(encoded, expected)
|
|
46
|
+
|
|
47
|
+
def test_encode_bytes_accented(self):
|
|
48
|
+
# アクセント付き文字のバイト列テスト
|
|
49
|
+
text = "Á¨ÍÓÚÂÊÔÀ"
|
|
50
|
+
expected = bytes([0x84, 0x86, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F]) # MSXブラジル文字セットの対応するバイト値
|
|
51
|
+
encoded = text.encode("msx-br")
|
|
52
|
+
self.assertEqual(encoded, expected)
|
|
53
|
+
|
|
54
|
+
def test_encode_bytes_graphic(self):
|
|
55
|
+
# グラフィック文字のバイト列テスト
|
|
56
|
+
text = "☺☻"
|
|
57
|
+
expected = bytes([0x01, 0x41, 0x01, 0x42]) # MSXブラジル文字セットの対応するバイト値
|
|
58
|
+
encoded = text.encode("msx-br")
|
|
59
|
+
self.assertEqual(encoded, expected)
|
|
60
|
+
|
|
61
|
+
def test_encode_bytes_mixed(self):
|
|
62
|
+
# 混合文字のバイト列テスト
|
|
63
|
+
text = "Aá"
|
|
64
|
+
expected = bytes([0x41, 0xA0]) # MSXブラジル文字セットの対応するバイト値
|
|
65
|
+
encoded = text.encode("msx-br")
|
|
66
|
+
self.assertEqual(encoded, expected)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
unittest.main()
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import codecs
|
|
3
|
+
from msx_charset import msx_charset
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestMSXCharsetIntl(unittest.TestCase):
|
|
8
|
+
@classmethod
|
|
9
|
+
def setUpClass(cls):
|
|
10
|
+
# テスト実行前にコーデックを登録
|
|
11
|
+
codecs.register(msx_charset)
|
|
12
|
+
|
|
13
|
+
def test_encode_decode_ascii(self):
|
|
14
|
+
text = "Hello, World!"
|
|
15
|
+
encoded = text.encode("msx-intl")
|
|
16
|
+
decoded = encoded.decode("msx-intl")
|
|
17
|
+
self.assertEqual(text, decoded)
|
|
18
|
+
|
|
19
|
+
def test_encode_decode_accented_chars(self):
|
|
20
|
+
text = "áéíóúàèìòùâêîôû"
|
|
21
|
+
encoded = text.encode("msx-intl")
|
|
22
|
+
decoded = encoded.decode("msx-intl")
|
|
23
|
+
self.assertEqual(text, decoded)
|
|
24
|
+
|
|
25
|
+
def test_encode_decode_graphic_chars(self):
|
|
26
|
+
text = "☺☻♥♦♣♠"
|
|
27
|
+
encoded = text.encode("msx-intl")
|
|
28
|
+
decoded = encoded.decode("msx-intl")
|
|
29
|
+
self.assertEqual(text, decoded)
|
|
30
|
+
|
|
31
|
+
def test_encode_decode_mixed(self):
|
|
32
|
+
text = "Hello, áéíóú!"
|
|
33
|
+
encoded = text.encode("msx-intl")
|
|
34
|
+
decoded = encoded.decode("msx-intl")
|
|
35
|
+
self.assertEqual(text, decoded)
|
|
36
|
+
|
|
37
|
+
def test_codec_registration(self):
|
|
38
|
+
self.assertIsNotNone(codecs.lookup("msx-intl"))
|
|
39
|
+
self.assertIsNotNone(codecs.lookup("msx_intl"))
|
|
40
|
+
|
|
41
|
+
def test_encode_bytes_ascii(self):
|
|
42
|
+
# ASCII文字のバイト列テスト
|
|
43
|
+
text = "Hello!"
|
|
44
|
+
expected = bytes([0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21])
|
|
45
|
+
encoded = text.encode("msx-intl")
|
|
46
|
+
self.assertEqual(encoded, expected)
|
|
47
|
+
|
|
48
|
+
def test_encode_bytes_accented(self):
|
|
49
|
+
# アクセント付き文字のバイト列テスト
|
|
50
|
+
text = "áé"
|
|
51
|
+
expected = bytes([0xA0, 0x82]) # MSXインターナショナル文字セットの対応するバイト値
|
|
52
|
+
encoded = text.encode("msx-intl")
|
|
53
|
+
self.assertEqual(encoded, expected)
|
|
54
|
+
|
|
55
|
+
def test_encode_bytes_graphic(self):
|
|
56
|
+
# グラフィック文字のバイト列テスト
|
|
57
|
+
text = "☺☻"
|
|
58
|
+
expected = bytes([0x01, 0x41, 0x01, 0x42]) # MSXインターナショナル文字セットの対応するバイト値
|
|
59
|
+
encoded = text.encode("msx-intl")
|
|
60
|
+
self.assertEqual(encoded, expected)
|
|
61
|
+
|
|
62
|
+
def test_encode_bytes_mixed(self):
|
|
63
|
+
# 混合文字のバイト列テスト
|
|
64
|
+
text = "Aá"
|
|
65
|
+
expected = bytes([0x41, 0xA0]) # MSXインターナショナル文字セットの対応するバイト値
|
|
66
|
+
encoded = text.encode("msx-intl")
|
|
67
|
+
self.assertEqual(encoded, expected)
|
|
68
|
+
|
|
69
|
+
def test_encode_decode_currency(self):
|
|
70
|
+
text = "£$¥"
|
|
71
|
+
encoded = text.encode("msx-intl")
|
|
72
|
+
decoded = encoded.decode("msx-intl")
|
|
73
|
+
self.assertEqual(text, decoded)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if __name__ == "__main__":
|
|
77
|
+
unittest.main()
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import codecs
|
|
3
|
+
from msx_charset import msx_charset
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestMSXCharsetJP(unittest.TestCase):
|
|
7
|
+
@classmethod
|
|
8
|
+
def setUpClass(cls):
|
|
9
|
+
# テスト実行前にコーデックを登録
|
|
10
|
+
codecs.register(msx_charset)
|
|
11
|
+
|
|
12
|
+
def test_encode_decode_ascii(self):
|
|
13
|
+
text = "Hello, World!"
|
|
14
|
+
encoded = text.encode("msx-jp")
|
|
15
|
+
decoded = encoded.decode("msx-jp")
|
|
16
|
+
self.assertEqual(text, decoded)
|
|
17
|
+
|
|
18
|
+
def test_encode_decode_hiragana(self):
|
|
19
|
+
text = "こんにちは"
|
|
20
|
+
encoded = text.encode("msx-jp")
|
|
21
|
+
decoded = encoded.decode("msx-jp")
|
|
22
|
+
self.assertEqual(text, decoded)
|
|
23
|
+
|
|
24
|
+
def test_encode_decode_katakana(self):
|
|
25
|
+
text = "コンニチハ"
|
|
26
|
+
encoded = text.encode("msx-jp")
|
|
27
|
+
decoded = encoded.decode("msx-jp")
|
|
28
|
+
self.assertEqual(text, decoded)
|
|
29
|
+
|
|
30
|
+
def test_encode_decode_dakuten(self):
|
|
31
|
+
text = "がぎぐげご"
|
|
32
|
+
encoded = text.encode("msx-jp")
|
|
33
|
+
decoded = encoded.decode("msx-jp")
|
|
34
|
+
self.assertEqual(text, decoded)
|
|
35
|
+
|
|
36
|
+
def test_encode_decode_handakuten(self):
|
|
37
|
+
text = "ぱぴぷぺぽ"
|
|
38
|
+
encoded = text.encode("msx-jp")
|
|
39
|
+
decoded = encoded.decode("msx-jp")
|
|
40
|
+
self.assertEqual(text, decoded)
|
|
41
|
+
|
|
42
|
+
def test_encode_decode_graphic_chars(self):
|
|
43
|
+
text = "月火水木金土日"
|
|
44
|
+
encoded = text.encode("msx-jp")
|
|
45
|
+
decoded = encoded.decode("msx-jp")
|
|
46
|
+
self.assertEqual(text, decoded)
|
|
47
|
+
|
|
48
|
+
def test_encode_decode_mixed(self):
|
|
49
|
+
text = "Hello、こんにちは!"
|
|
50
|
+
encoded = text.encode("msx-jp")
|
|
51
|
+
decoded = encoded.decode("msx-jp")
|
|
52
|
+
self.assertEqual(text, decoded)
|
|
53
|
+
|
|
54
|
+
def test_codec_registration(self):
|
|
55
|
+
self.assertIsNotNone(codecs.lookup("msx-jp"))
|
|
56
|
+
self.assertIsNotNone(codecs.lookup("msx_jp"))
|
|
57
|
+
|
|
58
|
+
def test_encode_bytes_ascii(self):
|
|
59
|
+
# ASCII文字のバイト列テスト
|
|
60
|
+
text = "Hello!"
|
|
61
|
+
expected = bytes([0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21])
|
|
62
|
+
encoded = text.encode("msx-jp")
|
|
63
|
+
self.assertEqual(encoded, expected)
|
|
64
|
+
|
|
65
|
+
def test_encode_bytes_hiragana(self):
|
|
66
|
+
# ひらがなのバイト列テスト
|
|
67
|
+
text = "こんにちは"
|
|
68
|
+
expected = bytes([0x9A, 0xFD, 0xE6, 0xE1, 0xEA])
|
|
69
|
+
encoded = text.encode("msx-jp")
|
|
70
|
+
self.assertEqual(encoded, expected)
|
|
71
|
+
|
|
72
|
+
def test_encode_bytes_katakana(self):
|
|
73
|
+
# カタカナのバイト列テスト
|
|
74
|
+
text = "コンニチハ"
|
|
75
|
+
expected = bytes([0xBA, 0xDD, 0xC6, 0xC1, 0xCA])
|
|
76
|
+
encoded = text.encode("msx-jp")
|
|
77
|
+
self.assertEqual(encoded, expected)
|
|
78
|
+
|
|
79
|
+
def test_encode_bytes_dakuten(self):
|
|
80
|
+
# 濁点文字のバイト列テスト
|
|
81
|
+
text = "がぎ"
|
|
82
|
+
expected = bytes([0x96, 0xDE, 0x97, 0xDE])
|
|
83
|
+
encoded = text.encode("msx-jp")
|
|
84
|
+
self.assertEqual(encoded, expected)
|
|
85
|
+
|
|
86
|
+
def test_encode_bytes_handakuten(self):
|
|
87
|
+
# 半濁点文字のバイト列テスト
|
|
88
|
+
text = "ぱぴ"
|
|
89
|
+
expected = bytes([0xEA, 0xDF, 0xEB, 0xDF])
|
|
90
|
+
encoded = text.encode("msx-jp")
|
|
91
|
+
self.assertEqual(encoded, expected)
|
|
92
|
+
|
|
93
|
+
def test_encode_bytes_graphic(self):
|
|
94
|
+
# グラフィック文字のバイト列テスト
|
|
95
|
+
text = "月火"
|
|
96
|
+
expected = bytes([0x01, 0x41, 0x01, 0x42])
|
|
97
|
+
encoded = text.encode("msx-jp")
|
|
98
|
+
self.assertEqual(encoded, expected)
|
|
99
|
+
|
|
100
|
+
def test_encode_bytes_mixed(self):
|
|
101
|
+
# 混合文字のバイト列テスト
|
|
102
|
+
text = "A、あ"
|
|
103
|
+
expected = bytes([0x41, 0xA4, 0x91])
|
|
104
|
+
encoded = text.encode("msx-jp")
|
|
105
|
+
self.assertEqual(encoded, expected)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
if __name__ == "__main__":
|
|
109
|
+
unittest.main()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
msx_charset/__init__.py
|
|
7
|
+
msx_charset/codec_base.py
|
|
8
|
+
msx_charset/codec_br.py
|
|
9
|
+
msx_charset/codec_intl.py
|
|
10
|
+
msx_charset/codec_jp.py
|
|
11
|
+
msx_charset/tests/__init__.py
|
|
12
|
+
msx_charset/tests/test_charset_br.py
|
|
13
|
+
msx_charset/tests/test_charset_intl.py
|
|
14
|
+
msx_charset/tests/test_charset_jp.py
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=42", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "msx-charset"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{name = "yamamo-to", email = "humorum@gmail.com"}
|
|
10
|
+
]
|
|
11
|
+
description = "MSX character set codecs for Python"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.7"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.8",
|
|
19
|
+
"Programming Language :: Python :: 3.9",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
23
|
+
]
|
|
24
|
+
license = "MIT"
|
|
25
|
+
|
|
26
|
+
[tool.setuptools]
|
|
27
|
+
packages = ["msx_charset"]
|
|
28
|
+
license-files = []
|
|
29
|
+
|
|
30
|
+
[tool.pytest.ini_options]
|
|
31
|
+
testpaths = ["msx_charset/tests"]
|
|
32
|
+
python_files = ["test_*.py"]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Repository = "https://github.com/yamamo-to/msx-charset"
|
|
36
|
+
Issue = "https://github.com/yamamo-to/msx-charset/issues"
|
|
37
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="msx-charset",
|
|
5
|
+
version="0.1.0",
|
|
6
|
+
packages=find_packages(),
|
|
7
|
+
install_requires=[],
|
|
8
|
+
python_requires=">=3.8",
|
|
9
|
+
author="yamamo-to",
|
|
10
|
+
author_email="humorum@gmail.com",
|
|
11
|
+
description="MSX Japanese, International, and Brazilian character codec for Python",
|
|
12
|
+
long_description=open("README.md", encoding='utf-8').read(),
|
|
13
|
+
long_description_content_type="text/markdown",
|
|
14
|
+
url="https://github.com/yamamo-to/msx-charset",
|
|
15
|
+
classifiers=[
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.8",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
],
|
|
24
|
+
)
|