はじめに
プログラムで文字列の類似度を判定したい場面は多い。
スペルチェック、エラーメッセージでの候補提示、検索機能での曖昧マッチなどに利用される。
fstrcmp
は、文字列や配列の曖昧比較を行うライブラリとコマンドラインツールである。
GNU Gettextの曖昧比較機能をベースに開発されており、信頼性が高い。
環境
Ubuntu 24.04 LTS
fstrcmp 0.7
fstrcmpの特徴
比較アルゴリズム
- 編集距離(レーベンシュタイン距離)ベース
- 文字の挿入、削除、置換を考慮
- 0.0〜1.0の範囲で類似度を出力
対応データ
- ASCII文字列
- マルチバイト文字列(UTF-8)
- バイト配列
インストール
sudo apt update
sudo apt install fstrcmp
ログ
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages were automatically installed and are no longer required:
crack-common gyp libcares2 libgl1-amber-dri libglapi-mesa libjs-async libjs-events libjs-inherits
libjs-is-typedarray libjs-prettify libjs-regenerate libjs-source-map libjs-sprintf-js
libjs-typedarray-to-buffer libllvm17t64 liblttng-ust-common1t64 liblttng-ust-ctl5t64 liblttng-ust1t64
libnotify-bin libqt5x11extras5 libre2-10 libssl-dev libuv1-dev libxcb-damage0 mesa-utils-bin node-abbrev
node-ampproject-remapping node-ansi-regex node-ansi-styles node-aproba node-are-we-there-yet node-arrify
node-async node-async-each node-auto-bind node-babel-plugin-add-module-exports node-babel7-runtime
node-balanced-match node-base64-js node-binary-extensions node-brace-expansion node-busboy
node-camelcase node-caniuse-lite node-chownr node-chrome-trace-event node-ci-info node-cjs-module-lexer
node-cli-boxes node-cli-cursor node-clone node-collection-visit node-color-convert node-color-name
node-colors node-commander node-commondir node-concat-stream node-console-control-strings
node-convert-source-map node-core-js node-core-js-pure node-core-util-is node-data-uri-to-buffer
node-decompress-response node-deep-is node-defaults node-define-property node-delegates node-depd
node-diff node-electron-to-chromium node-encoding node-end-of-stream node-err-code node-error-ex
node-es-module-lexer node-escape-string-regexp node-eslint-utils node-eslint-visitor-keys node-esquery
node-estraverse node-esutils node-events node-fancy-log node-fast-deep-equal node-fast-levenshtein
node-fetch node-find-up node-flatted node-foreground-child node-fs-readdir-recursive
node-fs-write-stream-atomic node-fs.realpath node-function-bind node-get-caller-file node-get-stream
node-get-value node-glob node-globals node-got node-graceful-fs node-growl node-has-flag
node-has-unicode node-has-value node-has-values node-hosted-git-info node-iconv-lite node-ieee754
node-iferr node-imurmurhash node-indent-string node-inflight node-inherits node-ini node-interpret
node-ip node-ip-regex node-is-arrayish node-is-binary-path node-is-buffer node-is-descriptor
node-is-extglob node-is-path-cwd node-is-plain-obj node-is-plain-object node-is-stream
node-is-typedarray node-is-windows node-isarray node-isexe node-isobject node-js-tokens node-json-buffer
node-json-parse-better-errors node-json-schema node-json-schema-traverse node-json-stable-stringify
node-jsonify node-jsonparse node-kind-of node-levn node-loader-runner node-locate-path
node-lodash-packages node-lowercase-keys node-lru-cache node-map-visit node-memfs node-merge-stream
node-mimic-response node-minimatch node-minimist node-minipass node-mute-stream node-n3 node-negotiator
node-npm-run-path node-object-inspect node-object-visit node-once node-optimist node-optionator
node-osenv node-p-cancelable node-p-limit node-p-locate node-p-map node-pascalcase node-path-dirname
node-path-exists node-path-is-absolute node-path-is-inside node-path-type node-pify node-pkg-dir
node-postcss-value-parser node-prelude-ls node-process-nextick-args node-promise-inflight
node-promise-retry node-promzard node-prr node-pump node-punycode node-quick-lru node-randombytes
node-read node-readable-stream node-rechoir node-regenerator-runtime node-regenerator-transform
node-regexpp node-regjsgen node-repeat-string node-require-directory node-require-from-string
node-resolve node-resolve-cwd node-resolve-from node-restore-cursor node-resumer node-retry
node-run-queue node-safe-buffer node-serialize-javascript node-set-blocking node-set-immediate-shim
node-shebang-command node-shebang-regex node-shell-quote node-signal-exit node-slash node-slice-ansi
node-source-list-map node-source-map node-spdx-correct node-spdx-exceptions node-spdx-expression-parse
node-spdx-license-ids node-sprintf-js node-ssri node-stack-utils node-string-decoder node-strip-bom
node-supports-color node-tapable node-terser node-text-table node-through node-time-stamp
node-to-fast-properties node-tslib node-type-check node-typedarray node-typedarray-to-buffer node-undici
node-unicode-canonical-property-names-ecmascript node-unicode-match-property-value-ecmascript
node-unicode-property-aliases-ecmascript node-unset-value node-uri-js node-util-deprecate node-uuid
node-v8flags node-validate-npm-package-license node-wcwidth.js node-webpack-sources node-wordwrap
node-wrappy node-write-file-atomic node-xtend node-y18n node-yallist node-yaml nodejs-doc xbitmaps
Use 'sudo apt autoremove' to remove them.
The following additional packages will be installed:
libfstrcmp0
The following NEW packages will be installed:
fstrcmp libfstrcmp0
0 upgraded, 2 newly installed, 0 to remove and 48 not upgraded.
Need to get 15.5 kB of archives.
After this operation, 64.5 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://archive.ubuntu.com/ubuntu noble/universe amd64 libfstrcmp0 amd64 0.7.D001-3build1 [7562 B]
Get:2 http://archive.ubuntu.com/ubuntu noble/universe amd64 fstrcmp amd64 0.7.D001-3build1 [7910 B]
Fetched 15.5 kB in 1s (19.1 kB/s)
Selecting previously unselected package libfstrcmp0.
(Reading database ... 116786 files and directories currently installed.)
Preparing to unpack .../libfstrcmp0_0.7.D001-3build1_amd64.deb ...
Unpacking libfstrcmp0 (0.7.D001-3build1) ...
Selecting previously unselected package fstrcmp.
Preparing to unpack .../fstrcmp_0.7.D001-3build1_amd64.deb ...
Unpacking fstrcmp (0.7.D001-3build1) ...
Setting up libfstrcmp0 (0.7.D001-3build1) ...
Setting up fstrcmp (0.7.D001-3build1) ...
Processing triggers for man-db (2.12.0-4build2) ...
Processing triggers for libc-bin (2.39-0ubuntu8.5) ...
使ってみる
コマンドライン実行
fstrcmp "文字列1" "文字列2"
# 出力: 0.9000
※出力は0.0〜1.0の類似度スコア
# 完全一致
fstrcmp "hello" "hello"
# 出力: 1.0000
# 部分一致
fstrcmp "hello" "helo"
# 出力: 0.8889
# 全く異なる
fstrcmp "hello" "world"
# 出力: 0.2000
サンプル例
1. スペルチェック候補
# 正しいスペル: "receive"
fstrcmp "receive" "recieve"
# 出力: 0.8571
fstrcmp "receive" "recive"
# 出力: 0.9231
fstrcmp "receive" "recei"
# 出力: 0.8333
2. ファイル名の類似性
fstrcmp "document.txt" "Document.txt"
# 出力: 0.9167
fstrcmp "report_2025.pdf" "report_2024.pdf"
# 出力: 0.9333
fstrcmp "config.json" "config.yaml"
# 出力: 0.6364
3. コマンド名の候補提示
# "ls" の入力ミス
fstrcmp "ls" "sl"
# 出力: 0.5000
fstrcmp "ls" "lz"
# 出力: 0.5000
fstrcmp "grep" "gerp"
# 出力: 0.7500
4. 日本語文字列の比較
fstrcmp "こんにちは" "こんにちわ"
# 出力: 0.8667
fstrcmp "プログラム" "プログラミング"
# 出力: 0.7778
fstrcmp "データベース" "データーベース"
# 出力: 0.9231
閾値を使った判定
シェルスクリプトでの活用
#!/bin/bash
check_similarity() {
local str1="$1"
local str2="$2"
local threshold="$3"
score=$(fstrcmp "$str1" "$str2")
if (( $(echo "$score >= $threshold" | bc -l) )); then
echo "類似: $str1 ≈ $str2 (スコア: $score)"
else
echo "非類似: $str1 ≠ $str2 (スコア: $score)"
fi
}
# 使用例
check_similarity "hello" "helo" 0.8
check_similarity "hello" "world" 0.8
候補一覧からの検索
#!/bin/bash
candidates=("apple" "orange" "banana" "grape" "pineapple")
input="aple"
threshold=0.6
echo "入力: $input"
echo "候補:"
for candidate in "${candidates[@]}"; do
score=$(fstrcmp "$input" "$candidate")
if (( $(echo "$score >= $threshold" | bc -l) )); then
printf " %s (%.3f)\n" "$candidate" "$score"
fi
done
実行結果例:
入力: aple
候補:
apple (0.800)
実際の活用場面
エラーメッセージでの候補提示
コマンドが見つからない場合の候補表示
# 存在しないコマンド "grp" に対して
# "grep", "gzip", "groups" などから最も類似度の高いものを提示する
検索機能での部分マッチ
ファイル検索やデータベース検索でのマッチング
重複データの検出
- 顧客名の表記ゆれ検出
- 商品名の類似性チェック
- データクレンジング
参考
fstrcmp - Official Website
https://fstrcmp.sourceforge.net/GNU Gettext Manual
https://www.gnu.org/software/gettext/manual/gettext.htmlLevenshtein Distance - Wikipedia
https://en.wikipedia.org/wiki/Levenshtein_distance
おわりに
fstrcmp
は文字列の類似度判定のツールである。
コマンドラインでの簡単な比較から、プログラムでの利用までできるようだ。
実際に活用するとすれば、スペルチェック、検索機能、データクレンジング、候補一覧の提示などの場面で活用できそう。git
とかでもサブコマンド間違えると、実はこれじゃないみたいな候補を出してくれるけど、これもこういうの使っているのかな。