搜尋套件、儲存庫與 APP 分類

套件詳情v3.1.0

safe_text

一個用於從文字輸入中過濾不良詞彙並檢測各種格式(包括倍數詞)電話號碼的 Flutter 套件。

AndroidiOSWebmacOSWindowsLinux
近 30 天下載
4000
喜歡數
72
Pub 分數
160

安裝套件

flutter pub add safe_text

套件介紹

根據套件公開資料產生的選型評估,僅供參考。

safe_text 是一個 Flutter 套件,專為增強文字輸入安全性而設計,透過過濾不當用語並偵測多種格式的電話號碼(包括以倍數詞表示的號碼,例如「兩百」),提升內容安全。支援 Android、iOS、Web、macOS、Windows 與 Linux 的跨平台應用。此套件有助於維護使用者產生文字的內容完整性,非常適合聊天應用、表單與需內容審核的社群平台。可透過 pub.dev 隨意整合至 Flutter 專案,並提供可靠且即時的文字分析。

適用情境

  • 聊天應用
  • 使用者產生內容審核
  • 表單輸入清理
  • 社群平台安全
  • 從文字中提取電話號碼
  • 訊息應用中的內容過濾

主要特色

  • 不良詞彙過濾
  • 多格式電話號碼偵測
  • 對基於乘數的數字表達式的支援
  • 跨平台相容性
  • 與 Flutter 的輕鬆整合
  • 即時文字分析

適合對象

  • 開發安全訊息應用的開發者
  • 需要自動化內容審核的團隊
  • 處理使用者提交文字的應用程式
  • 需要電話號碼識別的項目
  • 專注於文字安全的Flutter開發者
  • 面向具有多樣化文字模式的全球受眾的應用程式

使用建議

  • 需要定期更新不良詞彙列表
  • 可能需要針對特定地區的粗俗用語進行客製化
  • 大文本批次的性能影響
  • 僅限預定義的檢測規則
  • 不適合深度語義分析
  • 取決於源詞庫的準確性

原始 README

以下為關聯原始碼儲存庫的 README 原文快照,最新內容請造訪原始碼儲存庫。

SafeText Banner

pub version pub likes pub points CI MIT license

platforms

A high-performance pure Dart package for filtering offensive language (profanity) and detecting phone numbers. Powered by the Aho-Corasick algorithm for O(N) single-pass scanning across 80+ languages and 55,000+ curated words.

💙 Find SafeText useful? A like on pub.dev or star on GitHub helps others discover it.


Table of Contents


Features

  • Scans thousands of bad words in a single pass of the input text.
  • Catches common character substitutions: @→a, 4→a, 3→e, 0→o, $→s, and more.
  • Detects phone numbers in digits, words, mixed formats, and multiplier words (e.g., "triple five").
  • Multiple masking strategies — full (******), partial (f**k), or custom replacement ([censored]).
  • Customizable — add your own words or exclude specific phrases.
  • No setup required — lazily auto-initializes with the full Language.english word list (~13k words) on first use; init is optional.
  • Non-blocking — PhoneNumberChecker runs in a separate isolate via Isolate.run.
  • Works on Android, iOS, Web, macOS, Linux, and Windows.

Installation

Add safe_text to your project using the Dart CLI:

dart pub add safe_text

Or manually add it to your pubspec.yaml:

dependencies:
  safe_text: ^3.0.0

Then run:

dart pub get

Quick Start

import 'package:safe_text/safe_text.dart';

void main() async {
  // Optional: initialize once at app startup with a specific language.
  // If you skip this, the filter lazily auto-initializes with the full
  // Language.english word list (lib/data/en.dart, ~13k words) on first use —
  // not the small legacy constants/badwords.dart list from v1.x/v2.x.
  SafeTextFilter.init(language: Language.english);

  // Filter profanity (full masking — default)
  final clean = SafeTextFilter.filterText(text: "What the f@ck!");
  print(clean); // "What the ****!"

  // Partial masking — keeps first & last characters for 4+ letter words
  final partial = SafeTextFilter.filterText(
    text: "What the f@ck!",
    strategy: const MaskStrategy.partial(),
  );
  print(partial); // "What the f**k!"

  // Custom replacement
  final custom = SafeTextFilter.filterText(
    text: "What the f@ck!",
    strategy: const MaskStrategy.custom(replacement: '[censored]'),
  );
  print(custom); // "What the [censored]!"

  // Check for bad words
  final hasBad = SafeTextFilter.containsBadWord(text: "Some bad input");
  print(hasBad); // true or false

  // Detect phone numbers
  final hasPhone = await PhoneNumberChecker.containsPhoneNumber(
    text: "Call me at nine 7 eight 3 triple four",
  );
  print(hasPhone); // true
}

API Reference

SafeTextFilter.init

Optional. Builds the Aho-Corasick trie from the selected word list(s). If you never call it, the filter lazily auto-initializes with Language.english (lib/data/en.dart, ~13k words) on first use of filterText / containsBadWord. Call it explicitly when you want a specific language or combination.

Upgrading from v2.x? In 2.x, an app that never called init fell back to the small legacy list in constants/badwords.dart (~1.7k words). As of 3.0.0, an uninitialized filter now lazily loads the full Language.english list instead — a much larger, different word list. If your app relied on the old, smaller list (e.g. "adult" was previously not flagged), see below for how to opt back into it.

// Single language
SafeTextFilter.init(language: Language.english);

// Custom combination
SafeTextFilter.init(languages: [Language.english, Language.hindi, Language.spanish]);

// All 75+ languages
SafeTextFilter.init(language: Language.all);
Parameter Type Default Description
language Language? Language.english A single language to load. Use Language.all to load every language. Ignored when languages is provided.
languages List<Language>? null A custom list of languages. Takes precedence over language.

Note: If neither parameter is provided, the filter defaults to Language.english.

SafeTextFilter.isInitialized & SafeTextFilter.reset

Check initialization status or reset loaded word lists dynamically (e.g., when switching languages). Because init auto-initializes on first use, you generally don't need to guard calls with isInitialized — but it's available if you want to check, and reset() lets you reload with a different language:

// Reset state to reload with a different language
SafeTextFilter.reset();
SafeTextFilter.init(language: Language.spanish);

SafeTextFilter.filterText

Synchronous. Returns the input text with matched bad words masked according to the chosen MaskStrategy.

// Full masking (default)
String result = SafeTextFilter.filterText(
  text: "Hello b4dass world!",
  extraWords: ["badterm"],      // optional: add custom words
  excludedWords: ["bass"],      // optional: never filter these
  useDefaultWords: true,        // use the built-in word list
);
// Result: "Hello ****** world!"

// Partial masking
String partial = SafeTextFilter.filterText(
  text: "Hello b4dass world!",
  strategy: const MaskStrategy.partial(),
);
// Result: "Hello b****s world!"

// Custom replacement
String custom = SafeTextFilter.filterText(
  text: "Hello b4dass world!",
  strategy: const MaskStrategy.custom(), // defaults to "[censored]"
);
// Result: "Hello [censored] world!"
Parameter Type Default Description
text String required The input string to process.
extraWords List<String>? null Additional words to filter on top of (or instead of) the built-in list.
excludedWords List<String>? null Words that must never be filtered, even if they appear in the list.
useDefaultWords bool true Include the built-in language word list. Set to false to use only extraWords.
strategy MaskStrategy? null (defaults to MaskStrategy.full()) Masking strategy. See Masking Strategies below.
fullMode bool true Deprecated. Use strategy instead. true maps to MaskStrategy.full(), false maps to MaskStrategy.partial().
obscureSymbol String * Deprecated. Pass obscureSymbol via MaskStrategy.full() or MaskStrategy.partial() instead.

Precedence: When strategy is provided, it takes full precedence over the deprecated fullMode and obscureSymbol parameters. When strategy is omitted, fullMode: true maps to MaskStrategy.full(obscureSymbol: obscureSymbol) and fullMode: false maps to MaskStrategy.partial(obscureSymbol: obscureSymbol).

Masking Strategies
Strategy Constructor Output Example Description
Full MaskStrategy.full(obscureSymbol: '*') badass → ****** Replaces every character with the obscure symbol.
Partial MaskStrategy.partial(obscureSymbol: '*') damn → d**n, ass → a** Keeps first character visible. For 4+ letter words, also keeps the last character.
Custom MaskStrategy.custom(replacement: '[censored]') badass → [censored] Replaces the entire word with a fixed string.

Note: obscureSymbol must be exactly one character. This is enforced via assert in debug mode — a multi-character string will trigger an AssertionError during development.


SafeTextFilter.containsBadWord

Asynchronous. Returns true if the text contains at least one filtered word.

bool hasBadWord = SafeTextFilter.containsBadWord(
  text: "Don't be a pendejo",
  extraWords: ["badterm"],   // optional
  excludedWords: ["pend"],   // optional
  useDefaultWords: true,     // optional
);
Parameter Type Default Description
text String required The input string to check.
extraWords List<String>? null Additional words to check against.
excludedWords List<String>? null Words to ignore even if matched.
useDefaultWords bool true Include the built-in word list in the check.
Keeping the legacy word list

If your app depends on the smaller v1.x/v2.x fallback list (constants/badwords.dart, ~1.7k words) instead of the full Language.english list (~13k words) that 3.0.0 lazily auto-initializes with, opt out of the default list and pass the legacy one in explicitly:

import 'package:safe_text/constants/badwords.dart';

bool hasBadWord = SafeTextFilter.containsBadWord(
  text: text,
  useDefaultWords: false,
  extraWords: badWords, // the legacy list from constants/badwords.dart
);

PhoneNumberChecker.containsPhoneNumber

Asynchronous. Runs in a separate isolate via Dart's Isolate.run so it never blocks the calling thread.

Detects phone numbers expressed as:

  • Pure digits: 9783444
  • Word-based: nine seven eight three four four four
  • Mixed: 9 seven 8 3444
  • Multiplier words: nine seven eight three triple four

Supported multiplier words: double, triple, quadruple, quintuple, sextuple, septuple, octuple, nonuple, decuple.

bool hasPhone = await PhoneNumberChecker.containsPhoneNumber(
  text: "Call me at nine 7 eight 3 triple four",
  minLength: 7,   // minimum digit count to be considered a phone number
  maxLength: 15,  // maximum digit count
);
Parameter Type Default Description
text String required The input string to check.
minLength int 7 Minimum number of digits for a valid phone number.
maxLength int 15 Maximum number of digits for a valid phone number.

Supported Languages

Pass any of these Language enum values to SafeTextFilter.init. Use Language.all to load every language simultaneously.

View all 82 supported languages
Enum Language
Language.afrikaans Afrikaans
Language.amharic Amharic
Language.arabic Arabic
Language.azerbaijani Azerbaijani
Language.belarusian Belarusian
Language.bulgarian Bulgarian
Language.catalan Catalan
Language.cebuano Cebuano
Language.czech Czech
Language.welsh Welsh
Language.danish Danish
Language.german German
Language.dzongkha Dzongkha
Language.greek Greek
Language.english English
Language.esperanto Esperanto
Language.spanish Spanish
Language.estonian Estonian
Language.basque Basque
Language.persian Persian
Language.finnish Finnish
Language.filipino Filipino
Language.french French
Language.scottishGaelic Scottish Gaelic
Language.galician Galician
Language.hindi Hindi
Language.croatian Croatian
Language.hungarian Hungarian
Language.armenian Armenian
Language.indonesian Indonesian
Language.icelandic Icelandic
Language.italian Italian
Language.japanese Japanese
Language.kabyle Kabyle
Language.kannada Kannada
Language.khmer Khmer
Language.korean Korean
Language.latin Latin
Language.lithuanian Lithuanian
Language.latvian Latvian
Language.maori Maori
Language.macedonian Macedonian
Language.malayalam Malayalam
Language.mongolian Mongolian
Language.marathi Marathi
Language.malay Malay
Language.maltese Maltese
Language.burmese Burmese
Language.dutch Dutch
Language.norwegian Norwegian
Language.norfuk Norfuk / Pitcairn
Language.piapoco Piapoco
Language.polish Polish
Language.portuguese Portuguese
Language.romanian Romanian
Language.kriol Kriol
Language.russian Russian
Language.slovak Slovak
Language.slovenian Slovenian
Language.samoan Samoan
Language.albanian Albanian
Language.serbian Serbian
Language.swedish Swedish
Language.tamil Tamil
Language.telugu Telugu
Language.tetum Tetum
Language.thai Thai
Language.klingon Klingon
Language.tongan Tongan
Language.turkish Turkish
Language.ukrainian Ukrainian
Language.uzbek Uzbek
Language.vietnamese Vietnamese
Language.yiddish Yiddish
Language.chinese Chinese
Language.zulu Zulu
Language.bengali Bengali
Language.gujarati Gujarati
Language.punjabi Punjabi
Language.swahili Swahili
Language.urdu Urdu
Language.all All of the above

How it Works

Legacy approach (v1.x): For each bad word in a list of 10,000+ words, run a separate regex scan over the entire input — O(W × N) where W is the word count.

v2.0.0 approach: The Aho-Corasick algorithm builds a Finite State Automaton (Trie) once from the entire word list. The engine then scans the input exactly once, matching all patterns simultaneously in O(N) time where N is the length of the text — regardless of how many words are in the list.

Input text  ──► [Normalizer] ──► [Aho-Corasick FSA] ──► Match ranges ──► [StringBuffer] ──► Filtered text
                  (leet-speak)     (single O(N) pass)    (merged)         (single-pass)

Migrating from v1.x

The original SafeText class is still available but marked @Deprecated. It internally delegates to the new classes. Migrate when ready:

v1.x v2.0.0
SafeTextFilter.init(...) Recommended — call once at startup. If skipped, containsBadWord/filterText fall back to the small legacy constants/badwords.dart list (~1.7k words) instead of the full multilingual dataset.
SafeText.filterText(text: ...) SafeTextFilter.filterText(text: ...)
await SafeText.containsBadWord(text: ...) SafeTextFilter.containsBadWord(text: ...)
await SafeText.containsPhoneNumber(text: ...) await PhoneNumberChecker.containsPhoneNumber(text: ...)

Before:

// v1.x — no init required, but slow
bool bad = await SafeText.containsBadWord(text: "some input");

After:

// v2.0.0 — init once, then use anywhere
SafeTextFilter.init(language: Language.english); // once, e.g. in main()
bool bad = SafeTextFilter.containsBadWord(text: "some input");

3.0.0 changed this again: init became fully optional. If you never call it, the filter now lazily auto-initializes with the full Language.english list (~13k words) — not the small legacy list above. See Keeping the legacy word list if you're upgrading from 2.x and relied on the smaller fallback.


Limitations

  • Skipping init is not behavior-preserving across major versions. An uninitialized filter now lazily loads the full Language.english list (~13k words); in 2.x, an uninitialized filter fell back to the small legacy constants/badwords.dart list (~1.7k words) instead. If you're upgrading from 2.x, see Keeping the legacy word list.
  • Phone number detection is English-word based. Words like "nine", "triple", etc. are English only — the detector does not parse written numbers in other languages.
  • False positives on technical terms. Short words in the filter list may match substrings of unrelated technical terms. Use excludedWords to suppress known false positives.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for the full guidelines. The short version:

  1. Clone the repo and check out the develop branch.
  2. Create a feature branch: git checkout -b feature/your-feature
  3. Add tests for any new behaviour.
  4. Run checks before submitting:
    dart analyze
    dart test
    
  5. Open a pull request targeting develop. Ensure CI passes.

For major changes, please open an issue first to discuss the approach.


Data Source

SafeText uses the List of Dirty, Naughty, Obscene, and Otherwise Bad Words dataset:

  • 80+ dialects and languages
  • 55,000+ curated words

We are grateful to the contributors of this dataset for providing a robust multilingual foundation.


Authors

Ronit Rameja
Ronit Rameja

LinkedIn • Report an Issue • Discussions • Buy me a coffee


Contributors

Thanks to everyone who has contributed to SafeText!

Contributors

Made with contrib.rocks

所屬分類

原始碼儲存庫

使用此套件的專案

暫無相關資料。