MatchSkeleton - Equivalent to MatchData with less memory use
This package provides the class MatchSkeleton. It behaves almost exactly like MatchData, except it uses a greatly less and practically negligible internal memory.
The built-in MatchData class holds a copy of the original String, from which the matched data are derived, in a “freeze” state. It is useful because no one can by chance destructively modify the original string. However, if is memory-savvy. Even if MatchData is the match of the first few characters of a 1-GB string, it internally holds the entire 1-GB of the original string. If a code running holds 1000 of them, it needs a memory use of 1TB(!).
This class holds the same information of the matched data as MatchData but as positional indices, and the original String object only. Therefore, as long as the original String is not destructively modified by an external process, any method of this class returns the equal result as MatchData. Note that while the instance of this class is kept, the original string is not garbage-collected by the Ruby interpreter.
One additional function this class offers is the instance variable and method pos_begin. It can be set by a user and hold the information (Integer) at which position the Regexp match has started to generate the matched data.
Note this library, when required, also modifies the operator MatchData#== so that it can be compared with MatchSkeleton objects. Now the operator is simply based on duck-typing of #string, #regexp, and #pre_match. MatchData#eql? is not affected, and therefore any comparison between MatchData and MatchSkeleton objects with MatchData#eql? or MatchSkeleton#eql? returns false.
Install
The standard procedure to install a gem should work:
gem install match_skeleton
Or, get it from https://rubygems.org/gems/match_skeleton
Then just require as
require 'match_skeleton'
Have fun!
Simple Examples
Here are some simple examples.
require 'match_skeleton'
str = "Something_Big."
pos = 3
mtch = str.match(/(.)big/i, pos)
mskn = MatchSkeleton.new(mtch, str, pos_begin: pos)
mtch == mskn # => true
mskn.string # => "Something_Big."
mskn[1] # => "_"
mskn.pos_begin # => 3
mskn.post_match # => "."
mtch.post_match # => "."
str[-1,1] = '%'
mskn.post_match # => "%" # The original string has been destructively modified. Do not do that...
mtch.post_match # => "."
mtch == mskn # => false
Known bugs
-
None.
This library has been tested in Ruby 2.0 or later only. It may work in Ruby 1.8, but has not been tested.
Extensive tests have been performed, as included in the package.
Acknowledgement
This work is supported by Wise Babel Ltd.
Copyright etc
- Author
-
Masa Sakano < imagine a_t sakano dot co dot uk >
- License
-
MIT.
- Warranty
-
No warranty whatsoever.
- Versions
-
The versions of this package follow Semantic Versioning (2.0.0) semver.org/
MatchSkeleton - MatchDataに等価でメモリを節約するクラス
クラス MatchSkeleton のGemです。MatchDataとほぼ完全に等価な動作をします。ただし、メモリ使用量は比較してはるかに少なくなり、ほぼ無視できます。
組込MatchDataクラスは、正規表現マッチした元の文字列(String)のコピーを“freeze”した状態で保持します。おかげで、外部のプロセスが元文字列を破壊的に変更してMatchDataのオブジェクトも影響を受ける、ということはありません。しかし、それはメモリ使用量が巨大になり得ます。たとえば、MatchDataオブジェクトが1GBの文字列の最初の数文字だけのマッチだったとしても、同オブジェクトは、その1GBの文字列を内部的に保持します。もし動作中のコードがそんなオブジェクトを1000個保持していたら、それだけで 1TB(!)のメモリを消費することになります。
このクラスは、MatchDataと同じ情報を保持しますが、それは内部的に、インデックスと(コピーではない)原文字列そのものだけです。したがって、原文字列が外部のプロセスで破壊的に変更されない限り、このクラスのメソッドの返り値は、MatchDataと同じです。念のため、このクラスのインスタンスが生きている限り、原文字列がガーベージ・コレクトされることはありません。
一点、このクラス独自のパラメーターとして、インスタンス変数かつメソッドのpos_beginが導入されています。正規表現マッチの開始ポジション(Integer)を(ユーザーが設定することで)保持します。
なお、このライブラリを require した時、演算子 MatchData#== が変更され、MatchSkeleton と比較できるようになります。結果、同演算子は、ダック・タイピングとして、#string, #regexp, および #pre_matchに依存するようになります。一方、MatchData#eql? は影響を受けません。すなわち、MatchData#eql? あるいは MatchSkeleton#eql?によって、MatchData と MatchSkeleton オブジェクトを比較すると常に偽(false)を返します。
インストール
gem を使ってインストールできます。
gem install match_skeleton
もしくは以下から入手して下さい。
https://rubygems.org/gems/match_skeleton
あとは、以下で一発です。
require 'match_skeleton'
お楽しみあれ!
単純な使用例
以下に幾つかの基本的な使用例を列挙します。
require 'match_skeleton'
str = "Something_Big."
pos = 3
mtch = str.match(/(.)big/i, pos)
mskn = MatchSkeleton.new(mtch, str, pos_begin: pos)
mtch == mskn # => true
mskn.string # => "Something_Big."
mskn[1] # => "_"
mskn.pos_begin # => 3
mskn.post_match # => "."
mtch.post_match # => "."
str[-1,1] = '%'
mskn.post_match # => "%" # 元文字列が破壊的に変更された結果。そんなことはしないように……。
mtch.post_match # => "."
mtch == mskn # => false
既知のバグ
-
なし。
このライブラリは Ruby 2.0 以上でのみ挙動試験されています。1.8以前でも動くかもしれませんが、テストされていません。
パッケージに含まれている通り、網羅的なテストが実行されています。
謝辞
この開発は、ワイズバベル社(Wise Babel Ltd)に支援されています。
著作権他情報
- 著者
-
Masa Sakano < imagine a_t sakano dot co dot uk >
- 利用許諾条項
-
MIT.
- 保証
-
一切無し。
- バージョン
-
Semantic Versioning (2.0.0) semver.org/