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
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
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
8
6.7k
port-monolith-to-wasm-for-chrome-extension
rhysd
0
590
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
CSS2026:OWS研究会・招待講演「世界観を、実装する」
atsush1_sada
2
340
契約で守るコンパウンドプロダクトのデザインシステム
yug1224
1
1.5k
FinOps Agentが生んだ技術負債:コスト自動調査の落とし穴と解消までの道のり
oasis1994liveforever
3
300
野良MCPサーバーを排除せよ!MCPサーバーのガバナンス
yukiogawa
1
240
BacklogのRAG 今ならこう作る - S3 Vectorsと自前パイプラインの勘所
revsystem
0
140
reInvent2026stby LT00 "Change your life!"
shinichirokawano
1
300
Agent × Maestro で始める モバイル E2E 端末準備からテスト実行・結果確認まで
sansantech
PRO
0
210
Vue.jsのGitHubから学ぶ意思決定
yut0naga1_fa
1
280
ガチで放置できるClaude Code実行環境の作り方.pdf
lamaglama39
5
9.8k
200人の配信コメント、 全部Jevが仕分けます 〜 マサカリガードを作ってみた 〜
katayamatg
0
130
AIに任せられるFlutterコードベースを作る 〜仕様をコードで表し、ハーネスで守る〜
myohei
1
120
DevelopersIO2026 -バックアップは“消されないこと”が9割-
yoshida0129
0
410
Featured
See All Featured
GraphQLとの向き合い方2022年版
quramy
50
15k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
650
How GitHub (no longer) Works
holman
316
150k
Typedesign – Prime Four
hannesfritz
42
3.2k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
BBQ
matthewcrist
90
10k
Side Projects
sachag
456
43k
Bash Introduction
62gerente
615
220k
GitHub's CSS Performance
jonrohan
1033
470k
The Curious Case for Waylosing
cassininazir
1
580
How to make the Groovebox
asonas
2
2.5k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
500
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 に よる検索実装)