Segmenter¶
Segmenter(lang, *, abbreviations=None, tokens=None)
Segmenter of texts in one language: it gives the tokens and the sentences of a text as spans of it, and the document of a text. The text is never changed. A segmenter is immutable: create it once and use it throughout the program, from several threads at once, which segment long texts in parallel; it can be pickled and equals the segmenters of the same language and lists.
Exceptions:
ValueError- the language is not supported, an abbreviation is not a word of letters, or a token is empty, has whitespace or control characters or starts or ends with an invisible separator;TypeError-abbreviationsortokensis a string or holds something other than strings.
from anyseg import Segmenter
segmenter = Segmenter("ru")
segmenter.tokenize("Ёж идёт домой")
[Span(start=0, end=2, text='Ёж'), Span(start=3, end=7, text='идёт'), Span(start=8, end=13, text='домой')]
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
lang |
str |
- | ISO 639-1 code of the language: "ru" |
abbreviations |
Iterable[str] |
None |
More abbreviations: words that keep a period after them |
tokens |
Iterable[str] |
None |
Strings that are one token each |
The object keeps them read-only: lang is the code of the language, abbreviations and tokens are sorted tuples of the lists.
Lists of your own¶
The rules of a language know the common abbreviations and the usual kinds of tokens; a text of a special field may need more.
- Abbreviations are words that keep a period after them:
"сущ"or"сущ.", in any case. Such a word with its period is one token and ends a sentence as the abbreviations of the language do. The segmenter keeps them lowercase, without the period and the stress marks. - Tokens are strings that are one token each, as written:
"C++","т.н.". A string matches where a token would start and no letter or digit adjoins it; of several strings that match at one place, the longest wins.
custom = Segmenter("ru", abbreviations=["сущ."], tokens=["C++", "т.н."])
[span.text for span in custom.tokenize("Язык C++ - т.н. сущ. язык")]
custom
['Язык', 'C++', '-', 'т.н.', 'сущ.', 'язык']
Segmenter('ru', abbreviations=('сущ',), tokens=('C++', 'т.н.'))
Methods¶
Tokens of a text¶
tokenize(text)
The tokens of the text in order. Whitespace, control characters and the invisible separators - zero width space, word joiner, byte order mark, and a soft hyphen and zero width (non-)joiner outside a word - separate the tokens and are in none of them. How a language splits its text, see Russian.
| Parameter | Type | Default | Description |
|---|---|---|---|
text |
str |
- | Text |
Exceptions:
UnicodeEncodeError- the text contains a lone surrogate.
[span.text for span in segmenter.tokenize("Ёж идёт, т. е. бежит: https://example.ru 😀")]
['Ёж', 'идёт', ',', 'т.', 'е.', 'бежит', ':', 'https://example.ru', '😀']
Sentences of a text¶
sentenize(text)
The sentences of the text in order, each from the start of its first token to the end of its last one. A paragraph - the part of the text between blank lines - always starts a sentence; inside it, final marks, abbreviations, emoticons and line breaks end sentences by the rules of the language.
| Parameter | Type | Default | Description |
|---|---|---|---|
text |
str |
- | Text |
Exceptions:
UnicodeEncodeError- the text contains a lone surrogate.
text = "Кот спал в 1914 г. Затем ушёл. «Куда?» — спросил пёс."
[span.text for span in segmenter.sentenize(text)]
segmenter.sentenize(" Ёж идёт. Кот спит ")
['Кот спал в 1914 г.', 'Затем ушёл.', '«Куда?» — спросил пёс.']
[Span(start=1, end=9, text='Ёж идёт.'), Span(start=10, end=18, text='Кот спит')]
Document of a text¶
segment(text)
The document of the text: its tokens as tokenize gives them, one word per token, its sentences as sentenize gives them, its paragraphs and their lines. The document keeps the text and gives the parts as views of it.
| Parameter | Type | Default | Description |
|---|---|---|---|
text |
str |
- | Text |
Exceptions:
UnicodeEncodeError- the text contains a lone surrogate.
doc = segmenter.segment("Ёж идёт домой.\n\nКот спит")
[sentence.text for sentence in doc.sentences], len(doc.tokens)
(['Ёж идёт домой.', 'Кот спит'], 6)
Documents of texts¶
pipe(texts, *, threads=1, batch_size=1000)
The documents of many texts, as segment gives them, in the order of the texts. The texts are taken from the iterable as the documents are asked for, batch_size at a time, and every batch is segmented without the GIL, on up to threads threads - at most one per core and per 4 KB of the batch: other Python threads run meanwhile, and several threads speed up a large collection of texts even with the GIL. A text that is not a string or holds a lone surrogate raises its error after the documents of the texts before it and ends the iteration, as does an error of the iterable; an interrupt such as KeyboardInterrupt comes at once. One iterator serves one thread at a time: a call while another runs raises ValueError.
| Parameter | Type | Default | Description |
|---|---|---|---|
texts |
Iterable[str] |
- | Texts |
threads |
int |
1 |
Number of threads that segment a batch |
batch_size |
int |
1000 |
Number of texts in a batch |
Exceptions:
ValueError-threadsorbatch_sizeis less than 1;TypeError-textsis a string or not iterable, or a text is not a string;UnicodeEncodeError- a text contains a lone surrogate.
texts = ["Ёж идёт домой. Кот спит", "Утро", "Ночь наступила"]
[len(doc.sentences) for doc in segmenter.pipe(texts, threads=2)]
[2, 1, 1]
Functions¶
tokenize(text, *, lang), sentenize(text, *, lang) and segment(text, *, lang) do the same as the methods of Segmenter(lang): the module keeps one segmenter per language. The language is a keyword argument and has no default.
from anyseg import sentenize, tokenize
[span.text for span in tokenize("Мама мыла раму", lang="ru")]
[span.text for span in sentenize("Мама мыла раму. Кот спит", lang="ru")]
['Мама', 'мыла', 'раму']
['Мама мыла раму.', 'Кот спит']
Span¶
Span(start, end, text)
A piece of a text with its position: start is the position of its first character, end the position after the last one, and text the piece. Positions are offsets in the characters of the Python string, as in its slices: text[span.start:span.end] == span.text. Spans are immutable, compare by all three attributes and can be pickled.
from anyseg import Span
text = "Ёж идёт"
span = Span(3, 7, "идёт")
span, text[span.start : span.end] == span.text
(Span(start=3, end=7, text='идёт'), True)
Rust¶
The segmenter is the Rust crate anyseg, with every language behind a Cargo feature: ru (Russian, on by default). It has the same Segmenter with tokenize, sentenize and segment, and gives positions in bytes of the UTF-8 string.
use anyseg::Segmenter;
let segmenter = Segmenter::new("ru").unwrap();
let text = "Мама мыла раму";
let tokens: Vec<&str> = segmenter.tokenize(text).iter().map(|span| span.slice(text)).collect();
assert_eq!(tokens, ["Мама", "мыла", "раму"]);