Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

2012.11.17 CLR/H&札幌C++勉強会 発表資料「部分文字列の取得を 効率よく!楽に! - fundoshi.hppの紹介と今後の予定 -」

1,875 views

Published on

Published in: Technology
  • Login to see the comments

2012.11.17 CLR/H&札幌C++勉強会 発表資料「部分文字列の取得を 効率よく!楽に! - fundoshi.hppの紹介と今後の予定 -」

  1. 1. 部分文字列の取得を 効率よく!楽に!~fundoshi.hppの紹介と今後の予定~H.Hiro (Maraigue) @札幌C++勉強会 main@hhiro.net Twitter: @h_hiro_
  2. 2. 自己紹介H.Hiro
  3. 3. 自己紹介H.Hiro• とりあえず Twitterの@h_hiro_か githubのmaraigue(まれーぐ)をご覧下さい
  4. 4. 以上
  5. 5. すみません端折りすぎました
  6. 6. 自己紹介H.Hiro• 大学院生やってます(情報系)• 趣味でもプログラム書いてます プログラミング歴15年(ただし、職業プログラミング歴は無し)
  7. 7. 自己紹介H.Hiro• 大学院生やってます(情報系)• 趣味でもプログラム書いてます• メインはRuby 札幌Ruby会議2012(9月14日~16日)のスタッフでした http://gihyo.jp/news/report/01/sapporo-rubykaigi2012
  8. 8. 自己紹介H.Hiro• 大学院生やってます(情報系)• 趣味でもプログラム書いてます• メインはRuby• C++は研究での利用がメイン  その中から汎用的に使えそうな部分を 切り出したのがfundoshi.hppです
  9. 9. fundoshi.hppとは
  10. 10. その前に
  11. 11. 部分文字列とは
  12. 12. 部分文字列とは文字列xに対し、xのi文字目, (i+1)文字目, ...,j文字目(0≦i≦j<x.length)からなる文字列をxの部分文字列(substring)という。std::string x("Sapporo.cpp");std::string y = x.substr(1, 5);// xの1文字目から5文字取得するので…std::cout << y << std::endl;// "appor"を表示
  13. 13. 部分文字列とはstd::string x("Sapporo.cpp");std::string y = x.substr(1, 5);// xの1文字目から5文字取得するので…std::cout << y << std::endl;// "appor"を表示これの内部処理は?
  14. 14. 部分文字列とはstd::string x("Sapporo.cpp");std::string y = x.substr(1, 5);// xの1文字目から5文字取得するので…std::cout << y << std::endl;// "appor"を表示メモリ(RAM)
  15. 15. 部分文字列とはstd::string x("Sapporo.cpp");std::string y = x.substr(1, 5);// xの1文字目から5文字取得するので…std::cout << y << std::endl;// "appor"を表示メモリ(RAM) Sapporo.cpp ↑ ↑ xの起点 xの終点
  16. 16. 部分文字列とはstd::string x("Sapporo.cpp");std::string y = x.substr(1, 5);// xの1文字目から5文字取得するので…std::cout << y << std::endl;// "appor"を表示メモリ(RAM) Sapporo.cpp appor ↑ ↑ ↑ ↑ xの起点 xの終点 yの起点 yの終点
  17. 17. 部分文字列とはstd::string x("Sapporo.cpp");std::string y = x.substr(1, 5);// xの1文字目から5文字取得するので…std::cout << y << std::endl; •文字数ぶんだけメモリを消費// "appor"を表示 •内容のコピーもしないとならないメモリ(RAM) Sapporo.cpp appor ↑ ↑ ↑ ↑ xの起点 xの終点 yの起点 yの終点
  18. 18. メモリ消費の問題を回避するいちいちコピーすると、メモリも時間も余計に必要メモリ(RAM) Sapporo.cpp appor ↑ ↑ ↑ ↑ xの起点 xの終点 yの起点 yの終点
  19. 19. メモリ消費の問題を回避するいちいちコピーすると、メモリも時間も余計に必要 ↓じゃあコピーしないでメモリを共有すればいい(ただし、xの内容が更新されない場合に限る)yの起点 yの終点 ↓メモリ(RAM) ↓ Sapporo.cpp ↑ ↑ xの起点 xの終点
  20. 20. メモリ消費の問題を回避するC#ユーザ Rubyユーザ Pythonユーザ そんな面倒なことしないよー。 メンテナンス性も悪くなるし。
  21. 21. メモリ消費の問題を回避するC#ユーザ Rubyユーザ Pythonユーザ C++ユーザ ポインタ使って、無駄なメモリ 使わないようにすればいいさ。 面倒だけどね…。
  22. 22. メモリ消費の問題を回避するC#ユーザ Rubyユーザ Pythonユーザ C++ユーザH.Hiro じゃあ面倒じゃなくしてやるよ! そのためのクラス作ってな!
  23. 23. それでは改めてfundoshi.hppとは
  24. 24. fundoshi.hppとは部分文字列をメモリを共有したまま取得するライブラリstd::string x("Sapporo.cpp");fundoshi::string y;y = fundoshi::string(x, 1, 5);std::cout << y << std::endl;x[5] = R;std::cout << y << std::endl;
  25. 25. fundoshi.hppとはstd::string x("Sapporo.cpp");fundoshi::string y;y = fundoshi::string(x, 1, 5);std::cout << y << std::endl;x[5] = R;std::cout << y << std::endl; Sapporo.cpp ↑ ↑ xの起点 xの終点
  26. 26. fundoshi.hppとは std::string x("Sapporo.cpp"); fundoshi::string y; y = fundoshi::string(x, 1, 5); std::cout << y << std::endl; x[5] = R;yの起点 yの終点 std::endl; std::cout << y << ↓ ↓ Sapporo.cpp ↑ ↑ xの起点 xの終点
  27. 27. fundoshi.hppとはstd::string x("Sapporo.cpp");fundoshi::string y;y = fundoshi::string(x, 1, 5);std::cout << y << std::endl;x[5] = R;std::cout << y << std::endl; “appor”を表示 Sapporo.cpp ↑ ↑ xの起点 xの終点
  28. 28. fundoshi.hppとはstd::string x("Sapporo.cpp");fundoshi::string y;y = fundoshi::string(x, 1, 5);std::cout << y << std::endl;x[5] = R;std::cout << y << std::endl; SappoRo.cpp ↑ ↑ xの起点 xの終点
  29. 29. fundoshi.hppとはstd::string x("Sapporo.cpp");fundoshi::string y;y = fundoshi::string(x, 1, 5);std::cout << y << std::endl;x[5] = R;std::cout << y << std::endl; SappoRo.cpp ↑ ↑ “appoR”を表示 xの起点 xの終点
  30. 30. ところで
  31. 31. 何でfundoshi なのか
  32. 32. fundoshiって名前の理由• 「他人のふんどしで相撲を取る」 が直接の由来• ふんどしって長いものだから stringに合ってるよねてことで採用 Photo by KAIZUKA Creative Commons BY-NC-SA 2.0 http://www.flickr.com/photos/kaizuka/386511394/
  33. 33. fundoshi.hppの 特徴
  34. 34. fundoshi.hppの制限事項• 元になる文字列の内容を書き換えると fundoshi側でも内容が書き換わります• fundoshi側から文字列の内容を書き換える ことはできません (const char * みたいなもの) std::string x("Sapporo.cpp"); fundoshi::string y; y = fundoshi::string(x, 1, 5); x[5] = R; // y[4] = R; // 不可!
  35. 35. fundoshi.hppの特長(1/2)std::string(C++標準のstring)と同じ感覚で使える• 自前でポインタを持つのと違って、 文字列長の情報とかも一緒にクラス内に 入っている。lengthメソッドとかもある。
  36. 36. fundoshi.hppの特長(1/2) std::string(C++標準のstring)と同じ感覚で 使える • メソッドのAPIは基本的に合わせてますconst char *p = "sapporo.cpp";fundoshi::string y(p, 7); // std::string y(p, 7); に相当y.length(); // std::stringのlengthと同様y[4]; //std::stringの[]演算子と同様y.begin(); // イテレータも取れる
  37. 37. fundoshi.hppの特長(1/2) std::string(C++標準のstring)と同じ感覚で 使える • メソッドのAPIは基本的に合わせてます • std::basic_string<T> に相当するものとして fundoshi::basic_string<T> がありますstd::basic_string<int> hoge; // 各文字がintで表されるような文字列fundoshi::basic_string<int> piyo; // fundoshi版
  38. 38. fundoshi.hppの特長(2/2)自前で関数を作るとき引数の型をfundoshi::stringとしておけばstd::stringも受け取れるint count_space(const fundoshi::string & s){ int result = 0; for(size_t i = 0; i < s.length(); ++i){ if(std::isspace(s[i])) ++result; } return result;}std::string buf("This is a pen.");count_space(buf); // 問題なし。3を返す
  39. 39. 実演
  40. 40. 使ってみよう"abcdefghijklmnopqrstuvwxyz"の空ではないすべての部分文字列を列挙する("a", "bcd", "defghijkl", ...)• std::stringだと ???byte• fundoshi::stringだと ???byte(インスタンス確保のための領域を除くと)
  41. 41. 使ってみよう"abcdefghijklmnopqrstuvwxyz"の空ではないすべての部分文字列を列挙する("a", "bcd", "defghijkl", ...)• std::stringだと 3276byte• fundoshi::stringだと 0byte(インスタンス確保のための領域を除くと)
  42. 42. 使ってみよう"abcdefghijklmnopqrstuvwxyz"の空ではないすべての部分文字列を列挙する("a", "bcd", "defghijkl", ...)• std::stringだと 3276byte n(n+1)(n+2)÷6 で計算可能• fundoshi::stringだと 0byte(インスタンス確保のための領域を除くと)
  43. 43. 使ってみよう"abcdefghijklmnopqrstuvwxyz"の空ではないすべての部分文字列を列挙する("a", "bcd", "defghijkl", ...)• std::stringだと 3276byte n(n+1)(n+2)÷6 で計算可能• fundoshi::stringだと 0byte(インスタンス確保のための領域を除くと)• 領域のサイズ:文字列長の3乗に比例• 文字列の個数:文字列長の2乗に比例
  44. 44. 応用例
  45. 45. 使い方(1/3)• もともとは、いろんな文字列アルゴリズムを 実装するのに欲しくなったので作った
  46. 46. 使い方(1/3)• もともとは、いろんな文字列アルゴリズムを 実装するのに欲しくなったので作った問題:文字列tから最速で部分文字列を検索するための(曖昧検索等は考慮しなくてよい)索引は?
  47. 47. 使い方(1/3)• もともとは、いろんな文字列アルゴリズムを 実装するのに欲しくなったので作った問題:文字列tから最速で部分文字列を検索するための(曖昧検索等は考慮しなくてよい)索引は?答え:tの部分文字列を全部格納しておく
  48. 48. 使い方(1/3)• もともとは、いろんな文字列アルゴリズムを 実装するのに欲しくなったので作ったSuffix Tree C ←"CACAO"の A O A Suffix Tree C C O (“CACAO”の O 部分文字列が A A 全部含まれてる) O O
  49. 49. 使い方(1/3)• もともとは、いろんな文字列アルゴリズムを 実装するのに欲しくなったので作ったSuffix Tree C ←"CACAO"の A O A Suffix Tree C C O (“CACAO”の O 部分文字列が A A メモリ量は 全部含まれてる) O テキスト長の2乗に比例 O →いくらなんでも多い
  50. 50. 使い方(1/3)• もともとは、いろんな文字列アルゴリズムを 実装するのに欲しくなったので作ったSuffix Tree C ←"CACAO"の A O A Suffix Tree C C O (“CACAO”の O 部分文字列が A A 全部含まれてる) O O
  51. 51. 使い方(1/3) • もともとは、いろんな文字列アルゴリズムを 実装するのに欲しくなったので作った fundoshi(4,1) Suffix Tree fundoshi(1,1) ←"CACAO"の fundoshi(0,2) Suffix Treefundoshi(4,1) (“CACAO”の 部分文字列が 全部含まれてる) fundoshi(4,1) fundoshi(2,3) fundoshi(2,3)
  52. 52. 使い方(1/3) • もともとは、いろんな文字列アルゴリズムを 実装するのに欲しくなったので作った fundoshi(4,1) Suffix Tree fundoshi(1,1) ←"CACAO"の fundoshi(0,2) Suffix Treefundoshi(4,1) (“CACAO”の 部分文字列が メモリ量は 全部含まれてる) テキスト長の比例で fundoshi(4,1) fundoshi(2,3) 済んじゃった! fundoshi(2,3)
  53. 53. 使い方(2/3) Webアプリケーションとかでも便利と思われる 例) 7文字を超えた部分を切り詰めて 「...」に置き換えたい 「本当にありがとうございました」→「本当にありがと...」//普通の方法if(buf.length() > 7) std::cout << buf.substr(0,7) << "..." << std::endl;else std::cout << buf << std::endl;
  54. 54. 使い方(2/3) Webアプリケーションとかでも便利と思われる 例) 7文字を超えた部分を切り詰めて 「...」に置き換えたい メモリがコピー 「本当にありがとうございました」→「本当にありがと...」//普通の方法 されちゃってるし!if(buf.length() > 7) std::cout << buf.substr(0,7) << "..." << std::endl;else std::cout << buf << std::endl;
  55. 55. 使い方(2/3) Webアプリケーションとかでも便利と思われる 例) 7文字を超えた部分を切り詰めて 「...」に置き換えたい 「本当にありがとうございました」→「本当にありがと...」//fundoshi.hppを使うとif(buf.length() > 7) std::cout << fundoshi::string(buf,0,7) << "..." << std::endl;else std::cout << buf << std::endl;
  56. 56. 使い方(3/3)Webアプリの裏方(フレームワークやWebサーバなど)でも便利と思われるSERVER_QUERY="hoge=11-17&piyo=NAME" ~~~~ ~~~~~ ~~~~ ~~~~ ↑欲しいのはこの4つ!※ C++のWebアプリフレームワークを 使ったことないのですが、このあたりの 事情をご存知の方いらっしゃったら 教えていただきたいです
  57. 57. 今後の展望
  58. 58. 今後の展望(1/2)必然的に部分文字列を取る関数はfundoshi::stringを返すと幸せになれるものが多いはず例) boost::match_results(正規表現などでの 検索結果の文字列を示すクラス)は std::stringを返すのだが、 fundoshi::stringで事足りることも多いよね→じゃあ自分で作ろうか
  59. 59. 今後の展望(2/2)ファイルストレージにも同様に適用できないか• 現状はRAM上の文字列にしか適用できない• 大容量のファイルを扱う場合などに便利• SSDなら読み込み時間の影響も少ない
  60. 60. おわりに
  61. 61. おわりに(1/2)fundoshi.hppのソースコードhttp://github.com/maraigue/fundoshi.hpp今回のデモ(部分文字列列挙)のソースコードhttp://github.com/maraigue/ clrhsapporocpp-20121117
  62. 62. おわりに(2/2)「部分文字列を取得するにあたって、メモリ余分に喰ってないか?」と思ったらfundoshi.hppのことを思い出して頂けると幸いです
  63. 63. ありがとうございました

×