패키지, 저장소 및 앱 카테고리 검색

패키지 상세v3.1.0

safe_text

텍스트 입력에서 부적절한 단어를 필터링하고 다양한 형식(다중 단어 포함)의 전화번호를 감지하기 위한 플러터 패키지입니다.

AndroidiOSWebmacOSWindowsLinux
30일 다운로드
4천
좋아요
72
Pub 점수
160

패키지 설치

flutter pub add safe_text

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

safe_text는 불건전한 단어를 필터링하고 다수의 형식(예: '이백'과 같은 배수 표현 포함)으로 표시된 전화번호를 탐지함으로써 텍스트 입력의 안전성을 높이기 위해 설계된 Flutter 패키지입니다. Android, iOS, Web, macOS, Windows, Linux에서 크로스플랫폼 애플리케이션을 지원합니다. 사용자 생성 텍스트의 콘텐츠 무결성을 유지하는 데 도움을 주며, 채팅 앱, 폼, 모더레이션이 중요한 커뮤니티 플랫폼에 적합합니다. pub.dev를 통해 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

카테고리

소스 저장소

이 패키지를 사용하는 프로젝트

아직 데이터가 없습니다.