Metadata-Version: 2.4
Name: pysinrom
Version: 0.1.1
Summary: Python tools for Sinitic romanization, currently only as research utilities for conversion between Jyutping and CantRomZJ1
License-Expression: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Text Processing :: Linguistic
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pycantonese<6,>=5.0
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Dynamic: license-file

# PySinRom

PySinRom provides Python utilities for Sinitic romanization processing. The current alpha release focuses on bidirectional conversion between Jyutping and CantRomZJ1, parsing CantRomZJ1 syllables, and representing converted syllables with PyCantonese `Jyutping` objects.

## Documentation update

This expanded README was uploaded after the submission deadline. Compared with the version made available before the deadline, this update adds only more detailed documentation and usage examples; the package code and functionality are unchanged. The pre-deadline release can be verified on the [PyPI page for PySinRom 0.1.0](https://pypi.org/project/pysinrom/0.1.0/).

## Installation

Install the package from PyPI:

```bash
pip install pysinrom
```

To install a local copy from the project directory:

```bash
python -m pip install .
```

PySinRom requires Python 3.10 or later and uses PyCantonese for Jyutping parsing.

## Quick start

```python
from pysinrom import (
    jyutping_to_cantromzj1,
    cantromzj1_to_jyutping,
)

cantromzj1, cantromzj1_syllables = jyutping_to_cantromzj1(
    "hoeng1gong2"
)

print(cantromzj1)
# heong1A|55gong2A|35

print(cantromzj1_syllables)
# ['heong1A|55', 'gong2A|35']

jyutping, jyutping_syllables = cantromzj1_to_jyutping(
    "heong1A|55gong2A|35"
)

print(jyutping)
# hoeng1gong2

print(jyutping_syllables)
# ['hoeng1', 'gong2']
```

## Public API overview

The following functions are exported directly from `pysinrom`:

| Function | Purpose |
| --- | --- |
| `jyutping_to_cantromzj1()` | Convert a string containing one or more Jyutping syllables to CantRomZJ1. |
| `jyutping_syllable_to_cantromzj1()` | Convert exactly one Jyutping syllable to CantRomZJ1. |
| `parse_jyutping_to_cantromzj1_objects()` | Parse Jyutping and return PyCantonese `Jyutping` objects whose fields contain CantRomZJ1 values. |
| `cantromzj1_to_jyutping()` | Convert a string containing one or more CantRomZJ1 syllables to Jyutping. |
| `cantromzj1_syllable_to_jyutping()` | Convert exactly one CantRomZJ1 syllable to Jyutping. |
| `parse_cantromzj1()` | Parse one or more CantRomZJ1 syllables into PyCantonese `Jyutping` objects. |
| `parse_cantromzj1_syllable()` | Parse exactly one CantRomZJ1 syllable into a PyCantonese `Jyutping` object. |

## Usage

### `jyutping_to_cantromzj1()`

Converts a string containing one or more Jyutping syllables to CantRomZJ1.

```python
from pysinrom import jyutping_to_cantromzj1

converted, syllables = jyutping_to_cantromzj1("hoeng1gong2")

print(converted)
# heong1A|55gong2A|35

print(syllables)
# ['heong1A|55', 'gong2A|35']
```

Both concatenated and space-separated Jyutping input are accepted:

```python
converted, syllables = jyutping_to_cantromzj1("hoeng1 gong2")

print(converted)
# heong1A|55gong2A|35
```

Use `output_separator` to control how the converted syllables are joined:

```python
converted = jyutping_to_cantromzj1(
    "hoeng1 gong2",
    output_separator=" ",
    return_mode="string",
)

print(converted)
# heong1A|55 gong2A|35
```

The supported `return_mode` values are:

- `"tuple"`: returns `(joined_string, syllable_list)`; this is the default.
- `"string"`: returns only the joined string.
- `"list"`: returns only the list of converted syllables.

```python
as_tuple = jyutping_to_cantromzj1("hoeng1gong2")
print(as_tuple)
# ('heong1A|55gong2A|35', ['heong1A|55', 'gong2A|35'])

as_string = jyutping_to_cantromzj1(
    "hoeng1gong2",
    return_mode="string",
)
print(as_string)
# heong1A|55gong2A|35

as_list = jyutping_to_cantromzj1(
    "hoeng1gong2",
    return_mode="list",
)
print(as_list)
# ['heong1A|55', 'gong2A|35']
```

An unsupported `return_mode` raises `ValueError`.

---

### `jyutping_syllable_to_cantromzj1()`

Converts exactly one Jyutping syllable to one CantRomZJ1 syllable.

```python
from pysinrom import jyutping_syllable_to_cantromzj1

result = jyutping_syllable_to_cantromzj1("hoeng1")

print(result)
# heong1A|55
```

Checked syllables ending in `p`, `t`, or `k` use the CantRomZJ1 checked-tone notation:

```python
result = jyutping_syllable_to_cantromzj1("sik6")

print(result)
# sik4B|2
```

The function expects exactly one valid Jyutping syllable. Input containing zero syllables or more than one syllable raises `ValueError`.

---

### `parse_jyutping_to_cantromzj1_objects()`

Parses a Jyutping string and returns a list of PyCantonese `Jyutping` objects whose `nucleus` and `tone` fields contain CantRomZJ1 values.

This function is useful when downstream code expects structured syllable objects rather than strings.

```python
from pysinrom import parse_jyutping_to_cantromzj1_objects

objects = parse_jyutping_to_cantromzj1_objects("hoeng1gong2")

first = objects[0]

print(first.onset)
# h

print(first.nucleus)
# eo

print(first.coda)
# ng

print(first.tone)
# 1A|55
```

Space-separated input is also accepted:

```python
objects = parse_jyutping_to_cantromzj1_objects("hoeng1 gong2")

print(len(objects))
# 2
```

Although the returned objects use the PyCantonese `Jyutping` class, their converted `nucleus` and `tone` fields follow CantRomZJ1 rather than standard Jyutping notation.

---

### `cantromzj1_to_jyutping()`

Converts a string containing one or more CantRomZJ1 syllables to Jyutping.

```python
from pysinrom import cantromzj1_to_jyutping

converted, syllables = cantromzj1_to_jyutping(
    "heong1A|55gong2A|35"
)

print(converted)
# hoeng1gong2

print(syllables)
# ['hoeng1', 'gong2']
```

Both concatenated and space-separated CantRomZJ1 input are accepted:

```python
converted = cantromzj1_to_jyutping(
    "heong1A|55 gong2A|35",
    output_separator=" ",
    return_mode="string",
)

print(converted)
# hoeng1 gong2
```

The function supports the same three `return_mode` values as `jyutping_to_cantromzj1()`:

```python
as_tuple = cantromzj1_to_jyutping(
    "heong1A|55gong2A|35"
)
print(as_tuple)
# ('hoeng1gong2', ['hoeng1', 'gong2'])

as_string = cantromzj1_to_jyutping(
    "heong1A|55gong2A|35",
    return_mode="string",
)
print(as_string)
# hoeng1gong2

as_list = cantromzj1_to_jyutping(
    "heong1A|55gong2A|35",
    return_mode="list",
)
print(as_list)
# ['hoeng1', 'gong2']
```

An unsupported `return_mode` raises `ValueError`.

---

### `cantromzj1_syllable_to_jyutping()`

Converts exactly one CantRomZJ1 syllable to one Jyutping syllable.

```python
from pysinrom import cantromzj1_syllable_to_jyutping

result = cantromzj1_syllable_to_jyutping("heong1A|55")

print(result)
# hoeng1
```

Checked-tone conversion is also supported:

```python
result = cantromzj1_syllable_to_jyutping("sik4B|2")

print(result)
# sik6
```

Invalid CantRomZJ1 syllables, unsupported tone suffixes, or syllables that cannot be divided into onset, nucleus, and coda raise `ValueError`.

---

### `parse_cantromzj1_syllable()`

Parses exactly one CantRomZJ1 syllable into a PyCantonese `Jyutping` object.

```python
from pysinrom import parse_cantromzj1_syllable

parsed = parse_cantromzj1_syllable("heong1A|55")

print(parsed.onset)
# h

print(parsed.nucleus)
# eo

print(parsed.coda)
# ng

print(parsed.tone)
# 1A|55
```

The returned object uses the PyCantonese field names `onset`, `nucleus`, `coda`, and `tone`. The field contents remain in CantRomZJ1 notation.

A syllable without a recognized CantRomZJ1 tone suffix, or a segmental body that cannot be parsed, raises `ValueError`.

---

### `parse_cantromzj1()`

Parses a string containing one or more CantRomZJ1 syllables into a list of PyCantonese `Jyutping` objects.

```python
from pysinrom import parse_cantromzj1

parsed = parse_cantromzj1("heong1A|55gong2A|35")

print(len(parsed))
# 2

print(parsed[0].onset)
# h

print(parsed[0].nucleus)
# eo

print(parsed[0].coda)
# ng

print(parsed[0].tone)
# 1A|55
```

Space-separated input is also accepted:

```python
parsed = parse_cantromzj1("heong1A|55 gong2A|35")

print(len(parsed))
# 2
```

For concatenated input, syllable boundaries are identified from valid CantRomZJ1 tone suffixes. Unparsed trailing content raises `ValueError`.

## Development status

PySinRom is research software released as an alpha version. Interfaces and supported romanization systems may be expanded in later releases.

## License

MIT License.
