Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
ripgrep をライブラリとして使う
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Linda_pp
November 24, 2021
Technology
790
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ripgrep をライブラリとして使う
Rust LT Online #5 発表資料
https://rust.connpass.com/event/228732/
Linda_pp
November 24, 2021
More Decks by Linda_pp
See All by Linda_pp
actionlint の Linter 設計
rhysd
7
6.7k
port-monolith-to-wasm-for-chrome-extension
rhysd
0
580
Fuzzing Rust Text Editor
rhysd
1
3.1k
Vim compiled to WebAssembly
rhysd
5
2.4k
about-neovim-0.4.0-floating-window
rhysd
3
2.4k
reply.vim
rhysd
0
1.4k
Vim ported to WebAssembly (VimConf 2018)
rhysd
4
3.6k
go-selfupdate-github で ツールを自己アップデートする
rhysd
5
4.7k
小さく始めて育てるコンパイラ
rhysd
13
5.1k
Other Decks in Technology
See All in Technology
覗いてみよう 関数型ビジュアル言語×2Dグラフィックスの世界
yohyamasaki
0
170
KanaAI
shreyas1009
0
140
ログラスのマルチプロダクトを 支える認証基盤 〜テナントごとに異なる統制とどう向き合うか〜
dada4386
3
330
高負荷プロダクション環境におけるAWS Lambdaのリアル 〜スケールとコストを左右する実行ライフサイクルの技術仕様〜
maimyyym
2
850
Claude Designがめちゃくちゃ便利なので使ってほしい
diggymo
0
260
AgentCoreで実践するハーネスエンジニアリング
yakumo
1
250
OpenSharing について熱く語る〜AI アセットの共有について〜
kameitomohiro
0
150
データ品質を壊しながらSnowflakeのAIに分析させてみた
kawanago
0
440
[2026-09-30]ロックンロールは鳴り止まないっ - 信頼性かまってちゃん - 「データ駆動を投げ捨ててまで。」追いかける信頼性改善に向けた取り組みの話
tosite
0
190
AI Made Us Faster at Solving the Wrong Problems
marceloancelmo
0
150
形式手法を使って仕様をコーディングしよう
mikanichinose
0
170
いちAWSエンジニアのAI活用を振り返る #devio2026 / devio osaka 2026 kawahara
masahirokawahara
2
330
Featured
See All Featured
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.6k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
750
Raft: Consensus for Rubyists
vanstee
142
7.7k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.9k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.3k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.2k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
SEO for Brand Visibility & Recognition
aleyda
0
4.8k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
290
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
Exploring anti-patterns in Rails
aemeredith
4
520
Believing is Seeing
oripsolob
1
240
Transcript
ripgrep をライブラリとして使う Twitter: @Linda_pp, GitHub: @rhysd Rust LT Online #5
(2021/11/23)
ripgrep とは 有名な grep 互換のコマンドラインツール.SIMD や マルチスレッドを活用し処理を高速化してい る..gitignore を見てくれたり出力に色を付けてくれ たりなど,ユーザフレンドリーな機能も提供.
pcre2 対応を除いて,すべて Rust で実装されてお り,ライブラリとしても使えるようにうまくモジュール化 されている.
活用例 hgrep (Human-friendly GREP) というツールでファイ ル検索に利用. 検索結果を良い感じにスニペットにまとめて構文ハイ ライトして出力するコマンドラインツール. - リポジトリ:
https://github.com/rhysd/hgrep - 紹介記事: https://rhysd.hatenablog.com/entry/2021/11/2 3/211530
TL;DR https://github.com/rhysd/hgrep/bl ob/main/src/ripgrep.rs ↑ここにすべての実装が入っている grep 出力 パーサ grep 実装 chunk
の 計算処理 Printer Bat Printer Syntect Printer ↓ ここの話 --no-ignore --ignore-case --smart-case --glob GLOB... --glob-case-insensitive --fixed-strings --word-regexp --follow --multiline --multiline-dotall --crlf --mmap --max-count NUM --max-depth NUM --max-filesize NUM+SUFFIX? --line-regexp --invert-match --pcre2 --type TYPE --type-not TYPE --type-list --one-file-system --no-unicode --regex-size-limit --dfa-size-limit
ripgrep のモジュール構造 ripgrep cli core ignore globpath matcher pcre2 regex
memmem memchr printer searcher ripgrep 用 CLI パーサ (grep-cli) 本体(main 関数はここ) ディレクトリを辿ってファイルパスを列挙 **/*.rs のような glob のファイルパス列挙 ファイルに対するマッチ処理 (grep-matcher) pcre2 の Rust binding 有名な regex crate libc の memmem の SIMD 実装 libc の memchr の SIMD 実装 ファイルの検索処理 (grep-searcher) マッチ結果の表示処理 (grep-printer)
ripgrep のモジュール構造 ripgrep cli core ignore globpath matcher pcre2 regex
memmem memchr printer searcher ripgrep 用 CLI パーサ (grep-cli) 本体(main 関数はここ) ディレクトリを辿ってファイルパスを列挙 **/*.rs のような glob のファイルパス列挙 ファイルに対するマッチ処理 (grep-matcher) pcre2 の Rust binding 有名な regex crate libc の memmem の SIMD 実装 libc の memchr の SIMD 実装 ファイルの検索処理 (grep-searcher) マッチ結果の表示処理 (grep-printer)
サンプルコード https://github.com/rhysd/misc/tree/master/rust/chibigrep - ripgrep のうち再帰的にファイルを検索してマッチ結果を 取得する処理部分だけを使う - 特定のテキストを含んだファイルを探してくるユースケー スを想定 -
ignore, grep-matcher, grep-searcher の3つの crate を 使う
ディレクトリの walker を生成 use ignore::{WalkBuilder, WalkState}; // Path を再帰的に辿る walker
を生成.今回は WalkParallel でマルチスレッドでパスを 辿る // スレッドプールは自動で生成される(スレッド数は指定もできるが,デフォルトで良い感じに決 めてくれる) let mut builder = WalkBuilder::new(path); for path in rest { builder.add(path); } builder .hidden(false) // 隠しファイルを検索 .ignore(true) // ignore されたファイルを無視 .parents(true); // 親ディレクトリを辿って .gitignore を探す let walker = builder.build_parallel();
ディレクトリをマルチスレッドで再帰的に辿る let (tx, rx) = mpsc::channel(); // walker.run はマルチスレッドで呼ばれるので値の受け渡しを channel
でやる walker.run(|| { // 初期化関数.ここはスレッドプールのスレッドごとに呼ばれる let tx = tx.clone(); Box::new(move |result| match result { // この内側のコールバックはファイルパスごとに呼ばれる Ok(entry) if entry.file_type().map(|t| t.is_file()).unwrap_or(false) => { // `entry` は `ignore::DirEntry` grep_file(pat, entry.into_path(), &tx); // ファイルの時.ファイル内を検索 ignore::WalkState::Continue // 検索を続ける } Ok(_) => ignore::WalkState::Continue, // ディレクトリの時.検索を続ける Err(err) => { tx.send(Err(format!("{}", err))).unwrap(); ignore::WalkState::Quit // 検索を中止する } }) });
マッチ結果を受け取る Sink を実装 use grep_searcher::{Sink, SinkMatch}; struct SearchSink<'a> { tx:
&'a Sender<Result<Match, MyError>>, path: &'a Path, } // 結果を集めるためのコールバックを Sink で実装.マッチ箇所ごとに `matched` が呼ばれる impl<'a> Sink for SearchSink<'a> { type Error = io::Error; // `SinkMatch` にマッチ情報が入っている fn matched(&mut self, _searcher: &Searcher, mat: &SinkMatch<'_>) -> Result<bool, Self::Error> { let m = Match { path: self.path.to_owned(), lnum: mat.line_number().unwrap_or(0), line: mat.bytes().to_vec(), }; self.tx.send(Ok(m)).unwrap(); // マッチ結果を返す Ok(true) } }
マッチ処理を行う matcher を生成 use grep_regex::RegexMatcherBuilder; let mut builder = RegexMatcherBuilder::new();
builder .case_smart(true) // smart case を有効に .unicode(true); // unicode 対応 // Matcher を生成.今回は regex crate を使った RegexMatcher を使う // これ以外にも pcre2 を使ったものもある let matcher = match builder.build(pat) { Ok(m) => m, Err(err) => { tx.send(Err(format!("{}", err))).unwrap(); return; } };
searcher を生成してファイル内を検索 use grep_searcher::{BinaryDetection, MmapChoice, SearcherBuilder}; // Searcher を生成 let
mut builder = SearcherBuilder::new(); builder .binary_detection(BinaryDetection::quit(0)) // バイナリファイルだと判明したら検索をやめる .line_number(true) .memory_map(unsafe { MmapChoice::auto() }); // mmap を有効にする let mut searcher = builder.build(); // ここでファイルを検索.マッチごとに sink の matched メソッドが呼ばれる let mut sink = SearchSink { tx, path: &path }; if let Err(err) = searcher.search_path(&matcher, &path, &mut sink) { tx.send(Err(format!("{}", err))).unwrap(); }
まとめ • ripgrep は個々の機能ごと複数の crate に分割して実装されている ◦ ファイルパス検索(ignore) ◦ マッチ処理(grep-regex,
grep-matcher) ◦ ファイル検索(grep-searcher) ◦ 結果表示(grep-printer) • 「特定のパターンのテキストを含んだファイルを探してくる」という処理に対してはか なり汎用的・簡単に使うことができ,実行効率も良い(マルチスレッド活用・SIMD に よる検索実装)