Skip to content

Commit e254e12

Browse files
docs: expand StringTrie documentation (#139)
1 parent 65abac6 commit e254e12

3 files changed

Lines changed: 121 additions & 1 deletion

File tree

README.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ Usage
3939

4040
See `tutorial`_ and `API`_ for details.
4141

42+
For immutable ``str -> str`` mappings, use ``marisa_trie.StringTrie``
43+
(implemented as two internal tries plus a compact ID mapping table).
44+
4245
.. _tutorial: https://marisa-trie.readthedocs.io/en/latest/tutorial.html
4346
.. _API: https://marisa-trie.readthedocs.io/en/latest/api.html
4447

@@ -50,7 +53,8 @@ Current limitations
5053
and doesn't have iterator counterpart;
5154
* ``read()`` and ``write()`` methods don't work with file-like objects
5255
(they work only with real files; pickling works fine for file-like objects);
53-
* there are ``keys()`` and ``items()`` methods but no ``values()`` method.
56+
* ``Trie``, ``BytesTrie`` and ``RecordTrie`` provide ``keys()`` and
57+
``items()`` methods but no ``values()`` method.
5458

5559
License
5660
=======

docs/tutorial.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,49 @@ Two read-only accessors are available for advanced usage:
157157
* ``key_trie``: the internal key trie (``marisa_trie.Trie``)
158158
* ``value_trie``: the internal value trie (``marisa_trie.Trie``)
159159

160+
Python equivalents of common CLI workflows:
161+
162+
* Build and save::
163+
164+
>>> pairs = [("apple", "fruit"), ("app", "prefix"), ("banana", "fruit")]
165+
>>> trie = marisa_trie.StringTrie(pairs)
166+
>>> trie.save("my_string_trie.bin")
167+
168+
* Exact lookup::
169+
170+
>>> trie.get("apple")
171+
"fruit"
172+
>>> trie.get("missing", "N/A")
173+
"N/A"
174+
175+
* Common prefix search (prefixes of a query key)::
176+
177+
>>> trie.prefixes("application")
178+
["app"]
179+
>>> trie.prefix_items("application")
180+
[("app", "prefix")]
181+
182+
* Predictive search (keys/items under a prefix)::
183+
184+
>>> trie.keys("app")
185+
["app", "apple"]
186+
>>> trie.items("app")
187+
[("app", "prefix"), ("apple", "fruit")]
188+
189+
* Dump all entries::
190+
191+
>>> list(trie.iteritems())
192+
[("app", "prefix"), ("apple", "fruit"), ("banana", "fruit")]
193+
194+
For large datasets, use the runnable bulk-build sample script::
195+
196+
$ python examples/build_string_trie.py input.tsv output.bin
197+
198+
``input.tsv`` must be UTF-8 text with one ``key<TAB>value`` pair per line.
199+
You can also stream from stdin::
200+
201+
$ cat input.tsv | python examples/build_string_trie.py - output.bin
202+
160203

161204
Persistence
162205
-----------

examples/build_string_trie.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env python3
2+
"""Build a StringTrie from TSV input.
3+
4+
Input format:
5+
one UTF-8 line per record, with "key<TAB>value"
6+
"""
7+
8+
from __future__ import annotations
9+
10+
import argparse
11+
import sys
12+
from contextlib import nullcontext
13+
14+
import marisa_trie
15+
16+
17+
def parse_args() -> argparse.Namespace:
18+
parser = argparse.ArgumentParser(
19+
description="Build a marisa_trie.StringTrie from TSV pairs."
20+
)
21+
parser.add_argument(
22+
"input",
23+
help="Input TSV path, or '-' for stdin.",
24+
)
25+
parser.add_argument(
26+
"output",
27+
help="Output binary path for StringTrie.save().",
28+
)
29+
parser.add_argument(
30+
"--progress-every",
31+
type=int,
32+
default=0,
33+
help="Print progress every N input lines (0 disables progress logs).",
34+
)
35+
return parser.parse_args()
36+
37+
38+
def iter_tsv_pairs(path: str, progress_every: int):
39+
if path == "-":
40+
ctx = nullcontext(sys.stdin)
41+
else:
42+
ctx = open(path, "r", encoding="utf-8", newline="")
43+
44+
with ctx as f:
45+
for lineno, raw in enumerate(f, 1):
46+
line = raw.rstrip("\n")
47+
if not line:
48+
continue
49+
if progress_every > 0 and lineno % progress_every == 0:
50+
print(f"read {lineno} lines", file=sys.stderr)
51+
if "\t" not in line:
52+
raise ValueError(
53+
f"line {lineno}: expected a TAB separator between key and value"
54+
)
55+
key, value = line.split("\t", 1)
56+
yield key, value
57+
58+
59+
def main() -> int:
60+
args = parse_args()
61+
try:
62+
trie = marisa_trie.StringTrie(
63+
iter_tsv_pairs(args.input, args.progress_every)
64+
)
65+
trie.save(args.output)
66+
except Exception as exc:
67+
print(f"error: {exc}", file=sys.stderr)
68+
return 1
69+
return 0
70+
71+
72+
if __name__ == "__main__":
73+
raise SystemExit(main())

0 commit comments

Comments
 (0)