res.add(new Match(s.to_s, i, s.length - i))
return res
end
+
+ # Is `self` in `s`?
+ protected fun is_in(s: Text): Bool do return search_index_in(s, 0) != -1
end
# BM_Pattern are pre-compiled string motif for the Boyer-Moore algorithm.
end
end
- # Compile a new motif
- init(motif: String)
+ init
do
- _motif = motif
_length = _motif.length
_gs = new Array[Int].with_capacity(_length)
- _bc_table = new ArrayMap[Char, Int]
compute_gs
compute_bc
end
# searched motif
- var _motif: String
+ private var motif: String
# length of the motif
- var _length: Int
+ private var length: Int is noinit
private fun bc(e: Char): Int
do
end
# good shifts
- var _gs: Array[Int]
+ private var gs: Array[Int] is noinit
# bad characters
- var _bc_table: Map[Char, Int]
+ private var bc_table = new ArrayMap[Char, Int]
private fun compute_bc
do
private fun compute_gs
do
- var x = _motif
var m = _length
var suff = suffixes
var i = 0
# Matches are a part of a `Text` found by a `Pattern`.
class Match
# The base string matched
- readable var _string: String
+ var string: String
# The starting position in the string
- readable var _from: Int
+ var from: Int
# The length of the matching part
- readable var _length: Int
+ var length: Int
# The position of the first character just after the matching part.
# May be out of the base string
- fun after: Int do return _from + _length
+ fun after: Int do return from + length
# The contents of the matching part
- redef fun to_s do return _string.substring(_from,_length)
+ redef fun to_s do return string.substring(from,length)
- # Matches `len` characters of `s` from `f`.
- init(s: String, f: Int, len: Int)
+ init
do
- assert positive_length: len >= 0
- assert valid_from: f >= 0
- assert valid_after: f + len <= s.length
- _string = s
- _from = f
- _length = len
+ assert positive_length: length >= 0
+ assert valid_from: from >= 0
+ assert valid_after: from + length <= string.length
end
end
# assert "I say hello to the world!".search_from("hello",7) == null
fun search_from(p: Pattern, from: Int): nullable Match do return p.search_in(self, from)
+ # Search the last occurence of the text `t`.
+ #
+ # assert "bob".search_last("b").from == 2
+ # assert "bob".search_last("bo").from == 0
+ # assert "bob".search_last("ob").from == 1
+ # assert "bobob".search_last("ob").from == 3
+ # assert "bobbob".search_last("bb").from == 2
+ # assert "bobbob".search_last("bob").from == 3
+ # assert "bob".search_last("z") == null
+ # assert "".search_last("b") == null
+ fun search_last(t: Text): nullable Match do
+ return search_last_up_to(t, length)
+ end
+
+ # Search the last occurence of the text `t` before `up_to`.
+ #
+ # assert "bobbob".search_last_up_to("b", 3).from == 2
+ # assert "bobbob".search_last_up_to("b", 6).from == 5
+ # assert "bobbob".search_last_up_to("b", 0) == null
+ fun search_last_up_to(t: Text, up_to: Int): nullable Match do
+ var i = up_to - t.length
+
+ while i >= 0 do
+ if substring(i, t.length) == t then
+ return new Match(self.to_s, i, t.length)
+ end
+ i -= 1
+ end
+ return null
+ end
+
# Search all occurrences of p into self.
#
# var a = new Array[Int]
# @deprecated alias for `split`
fun split_with(p: Pattern): Array[SELFTYPE] do return self.split(p)
+ # Split `self` on the first `=`
+ #
+ # assert "hello".split_once_on('l') == ["he", "lo"]
+ # assert "a, b, c, d, e".split_once_on(", ") == ["a", "b, c, d, e"]
+ fun split_once_on(p: Pattern): Array[SELFTYPE]
+ do
+ var m = p.search_in(self, 0)
+ if m == null then return [self]
+ return new Array[SELFTYPE].with_items(substring(0, m.from), substring_from(m.after))
+ end
+
# Replace all occurences of a pattern with a string
#
# assert "hlelo".replace("le", "el") == "hello"
return self.split_with(p).join(string)
end
- # Escape the four characters `<`, `>`, `&`, and `"` with their html counterpart
+ # Does `self` contains at least one instance of `pattern`?
#
- # assert "a&b->\"x\"".html_escape == "a&b->"x""
- fun html_escape: SELFTYPE
- do
- var ret = self
- if ret.chars.has('&') then ret = ret.replace('&', "&")
- if ret.chars.has('<') then ret = ret.replace('<', "<")
- if ret.chars.has('>') then ret = ret.replace('>', ">")
- if ret.chars.has('"') then ret = ret.replace('"', """)
- return ret
- end
+ # assert "hello".has('l')
+ # assert "hello".has("ll")
+ # assert not "hello".has("lll")
+ fun has(pattern: Pattern): Bool do return pattern.is_in(self)
end