Skip to content
Text docs0.2

Multi-pattern text search library

Latest stable Based on Text release 0.2.1

text-search implements an immutable generic Aho-Corasick automaton. It searches many keywords in one pass and associates each match with an application value. Options cover case handling, overlaps, word boundaries, Unicode normalization, and early-match behavior.

Text search flow

  • mutable builder and Kotlin DSL, producing an immutable automaton;
  • parseText, firstMatch, containsMatch, tokenize, and replaceAll;
  • generic match values and original-text offsets;
  • NONE, LATIN_ALPHA, and WHITESPACE_SEPARATED boundary modes;
  • NFC/NFKC normalization with offset mapping;
  • matchesAsFlow for coroutine collection.
dependencies {
implementation("io.github.bluetape4k.text:text-search:0.2.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:<compatible-version>") // Flow calls only
}
import io.bluetape4k.text.search.AhoCorasickAutomaton
import io.bluetape4k.text.search.SearchOptions
val automaton = AhoCorasickAutomaton.builder<String>()
.add("password reset", "ACCOUNT_TAKEOVER")
.add("card declined", "PAYMENT_RISK")
.options(SearchOptions(ignoreCase = true, allowOverlaps = false))
.build()
val matches = automaton.parseText("Password reset before card declined")
println(matches.map { it.value })
// [ACCOUNT_TAKEOVER, PAYMENT_RISK]

The builder is the configuration phase. After build(), share the automaton as an immutable snapshot.

OperationUse it when
parseTextall matches and offsets are needed now
firstMatchthe leftmost-longest match is sufficient
containsMatchonly a Boolean decision is needed
tokenizematched and unmatched fragments must be rendered separately
replaceAlleach accepted match becomes replacement text
matchesAsFlowthe surrounding coroutine pipeline benefits from collection and cancellation

tokenize always returns a non-overlapping sequence. allowOverlaps = false resolves competing matches before other operations consume them.

LATIN_ALPHA avoids matching a keyword inside a larger alphabetic word. WHITESPACE_SEPARATED is useful for phrases that must be surrounded by whitespace. Unicode normalization enables canonically or compatibility-equivalent input, but it adds measurable work; the 0.2.1 NFKC benchmark is much slower than the raw no-match path.

import io.bluetape4k.text.search.flow.matchesAsFlow
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.flow.toList
val firstAlert = automaton.matchesAsFlow("critical login before card declined")
.take(1)
.toList()

The Flow extension runs through channelFlow on Dispatchers.Default. Bounded collection prevents retaining unnecessary results, but the automaton still performs CPU work over the supplied text.

Define the keyword snapshot and option policy before publication. Rebuilding on every request repeats setup work. Match offsets refer to the original text even when normalization is enabled, which is why the implementation maintains offset mapping. Treat benchmark values as local comparisons under their recorded environment.

These diagrams are loaded directly from README assets published with the 0.2.1 release and pinned to its immutable commit. They describe this manual’s released structure and runtime flows, not later Snapshot changes. Select a preview to open the SVG at the same release commit.

Processing Flow diagram

Release README: text-search/README.md

text search Class Structure diagram

Release README: text-search/README.md

Search Pipeline diagram

Release README: text-search/README.md