npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ycookiey/yfuzzy

v0.1.2

Published

Japanese-aware fuzzy search library

Readme

yfuzzy

npm types minzipped license

日本語特化のあいまい検索ライブラリ。ローマ字混じり入力・ヘボン式/訓令式の同時照合・子音だけのマッチ・誤字許容を 1 パッケージに統合。依存ゼロ・ESM・TypeScript 型付き。

shinjuku / sinjuku / しんじゅく / シンジュク  →  すべて「シンジュク」にヒット
kmnr                                        →  「カミナリ」にヒット(子音だけ)
カナリ                                       →  「カミナリ」にヒット(とびとび一致)
センタイ                                     →  「センダイ」にヒット(誤字)

なぜ yfuzzy か

既存のあいまい検索ライブラリ(fuse.js / fuzzysort / MiniSearch / uFuzzy / match-sorter など)はラテン文字圏を前提に設計されており、diacritics(発音区別符号)の除去や Unicode 正規化には対応するものの、ローマ字とかなの変換や、ヘボン式・訓令式の違いを扱わない

日本語 UI では、利用者はローマ字・部分的なかな・子音だけ(上の例)で打つ一方、データはひらがな・カタカナ・漢字(の読み)で保持されている。yfuzzy はこの表記のずれを埋めることに特化している。

スコープ

向いている: 日本語の読み(かな)を索引にした短い文字列の検索。駅名・地名・商品名・人名などの読みに対する、逐次検索(type-ahead)やオートコンプリート。

向いていない:

  • 漢字をそのまま検索: yfuzzy は漢字を読みに変換しない(文字どおりの一致のみ)。読みで当てたいなら読み仮名を用意し getText で返す(使い方参照)。
  • ラテン文字の汎用あいまい検索 / 全文検索(複数フィールド・トークン化・TF-IDF): fuse.js / MiniSearch 等が成熟している。用途で使い分けるとよい。

類似パッケージとの比較

| 機能 | yfuzzy | fuse.js | fuzzysort | MiniSearch | uFuzzy | match-sorter | |---|:--:|:--:|:--:|:--:|:--:|:--:| | 日本語入力(ローマ字↔かな・ヘボン/訓令・かな正規化) | ✅ | ➖ | ➖ | ➖ | ➖ | ➖ | | 子音だけのマッチ | ✅ | ➖ | 🔸 | ➖ | 🔸 | 🔸 | | とびとび一致(subsequence) | ✅ | 🔸 | ✅ | ➖ | ✅ | 🔸 | | 誤字許容(編集距離) | ✅ | ✅ | ➖ | ✅ | 🔸 | ➖ | | ハイライト位置の返却 | ✅ | ✅ | ✅ | 🔸 | ✅ | ➖ | | 索引の事前構築 | ✅ | ✅ | ✅ | ✅ | ➖ | ➖ | | 全文検索(複数フィールド/トークン) | ➖ | ✅ | 🔸 | ✅ | ➖ | 🔸 | | ラテン文字の diacritics 除去 | ➖ | ✅ | ➖ | 🔸 | ✅ | ✅ | | 依存ゼロ | ✅ | ✅ | ✅ | ✅ | ✅ | ➖ |

凡例: ✅ 組み込み / 🔸 部分的・間接的(または要カスタム) / ➖ なし。各ライブラリの調査時点の既定挙動を基準とした。多くはカスタム関数で拡張できる。本表は「日本語入力対応+主要なあいまいマッチ機能」に観点を絞ったもの。

インストール

npm install @ycookiey/yfuzzy

Node 18+ / ESM 専用。

使い方

文字列配列

import { search } from '@ycookiey/yfuzzy';

const stations = ['トウキョウ', 'シンジュク', 'シブヤ', 'シナガワ'];

search('sinjuku', stations);
// → [{ item: 'シンジュク', refIndex: 1, score: 1, tier: 1 }]

オブジェクト配列(getText)

getText で検索対象の文字列を取り出す。漢字を読みで当てたい場合も、読み仮名を返せばよい(読みは利用者側で用意する)。

const items = [
  { label: '東京', yomi: 'トウキョウ' },
  { label: '新宿', yomi: 'シンジュク' },
];

search('しんじゅく', items, { getText: (x) => x.yomi });
// → [{ item: { label: '新宿', … }, refIndex: 1, score: 1, tier: 1 }]

索引の再利用(createIndex)

同じデータを繰り返し検索するなら事前構築する。単発 search と結果は同一。

import { createIndex } from '@ycookiey/yfuzzy';

const index = createIndex(stations);
index.search('しぶ');             // → 先頭は シブヤ(短い語なので tier3 候補も続く)
index.search('しな', { limit: 5 }); // 呼び出しごとに検索オプションを上書き

ハイライト(includeMatches)

includeMatches: true で、元文字列上の一致区間 [start, end)(半開・昇順、隣接や重複は統合済み)を返す(後述の tier 1・2 でのみ)。各区間を text.slice で切り出して囲めばハイライトになる。

const r = search('keki', ['ケーキ'], { includeMatches: true });
// r[0].matches → [[0, 3]]   ← 長音「ー」も含めて隙間なく連続

マッチの仕組み

クエリは tier 1 から順に評価され、最初に一致した tier で確定する(既定は tier 1〜3。maxTier: 4 で tier 4 も有効化)。score は 0〜1 で、上の tier ほど高い。

| tier | 内容 | 例 | score の範囲(目安) | |---|---|---|---| | 1 | 直接一致(かな/ローマ字が前方・部分一致) | シンジュクシンジュク | 0.75〜1.0 | | 2 | 柔軟一致(とびとびでも可。語頭・連続を優遇、子音だけの入力も可) | kmnrカミナリ | 0.5〜0.75 | | 3 | 誤字許容(編集距離、中間の置換/挿入/削除/入れ替え) | センタイセンダイ | 0.25〜0.5 | | 4 | 構造類似(2 文字単位の重なりによる類似〔Tversky 係数〕、既定で無効) | 大きく崩れた入力 | 0〜0.25 |

各 tier は幅およそ 0.25 の帯に収まり、スコアが tier 間の境界(0.25 / 0.5 / 0.75)ちょうどになることはない。そのため閾値ひとつで「確実なヒット」と「あいまいな候補(『もしかして』表示向け)」を分離できる。結果は score 降順(同点は refIndex 昇順で安定)。

API

search(query, items, options?)

単発検索。createIndex(items, options).search(query) と等価。

createIndex(items, options?) → SearchIndex

事前構築した索引を返す。index.search(query, searchOptions?) で呼び出しごとに検索オプションを上書きできる。index.size で件数。

オプション

構築時オプション(createIndex / searchoptions):

| 名前 | 型 | 既定 | 説明 | |---|---|---|---| | getText | (item: T) => string | なし | オブジェクト配列で検索対象文字列を取り出す(T[] のとき必須) | | romaji | 'hepburn' \| 'kunrei' \| 'both' \| false | 'both' | ローマ字照合の方式。false でローマ字照合せず、かなのみで照合 | | separatorExpansion | boolean \| string[] | false | 区切り文字を、取り除いた形と区切りとして扱う形の両方で照合(true['-', ' ', '・', '_']) |

検索時オプション(index.search で上書き可):

| 名前 | 型 | 既定 | 説明 | |---|---|---|---| | limit | number | 無制限 | 返却件数の上限 | | maxTier | 1 \| 2 \| 3 \| 4 | 3 | 実行する tier の上限(4 で構造類似の tier を有効化) | | minScore | number | 0 | この score 未満を除外 | | includeMatches | boolean | false | matches を含める |

結果 SearchResult<T>

type SearchResult<T> = {
  item: T;
  refIndex: number;                       // items 内の位置
  score: number;                          // 0〜1、高いほど良い
  tier: 1 | 2 | 3 | 4;
  matches?: readonly [number, number][];  // includeMatches 時、tier 1/2 のみ
};

性能

短い文字列の索引向け(数百〜数十万件)。内部の前段フィルタと早期打ち切りにより、1 クエリの実測値は千件で約 1.5ms、1 万件で約 10ms、10 万件で約 90ms(環境依存)。同条件で fuse.js より高速。maxTier を下げる、または romaji を一方の方式だけに絞ると更に軽くなる。索引構築は 10 万件で約 0.7 秒(一度きり)。

ライセンス

MIT。ローマ字→かな変換に WanaKana(MIT)のコードを改変のうえ同梱している。詳細は THIRD_PARTY_NOTICES.md