nitg: support for native_arg[cv] as intern
[nit.git] / lib / standard / string_search.nit
index 9e22e48..e15740d 100644 (file)
 # You  are  allowed  to  redistribute it and sell it, alone or is a part of
 # another product.
 
-# This module is about string search and matching.
-# It includes some good features
+# Basic string search, match and replace.
 package string_search
 
 import string
 
-# Patterns are string motifs.
-class Pattern
+# Patterns are abstract string motifs (include `String' and `Char').
+interface Pattern
        # Search `self' into `s' from a certain position.
        # Return the position of the first character of the matching section.
        # Return -1 if not found.
-       meth search_index_in(s: String, from: Int): Int is abstract
+       fun search_index_in(s: String, from: Int): Int is abstract
 
        # Search `self' into `s' from a certain position.
        # Return null if not found.
-       meth search_in(s: String, from: Int): Match is abstract
+       fun search_in(s: String, from: Int): nullable Match is abstract
 
-       # Search all `self' occucences into `s'.
-       meth search_all_in(s: String): Array[Match]
+       # Search all `self' occurrences into `s'.
+       fun search_all_in(s: String): Array[Match]
        do
                var res = new Array[Match] # Result
                var match = search_in(s, 0)
@@ -40,7 +39,7 @@ class Pattern
        end
 
        # Split `s' using `self' is separator.
-       meth split_in(s: String): Array[Match]
+       fun split_in(s: String): Array[Match]
        do
                var res = new Array[Match] # Result
                var i = 0 # Cursor
@@ -58,16 +57,17 @@ class Pattern
        end
 end
 
-# BM_Pattern are precompiled string motif for the Boyer-Moore Fast String Searching Algorithm
-# (cf. A Fast String Searching Algorithm, with R.S. Boyer.
-# Communications of the Association for Computing Machinery, 20(10), 1977, pp. 762-772.)
-# see also http://www.cs.utexas.edu/users/moore/best-ideas/string-searching/index.html
+# BM_Pattern are pre-compiled string motif for the Boyer-Moore algorithm.
+# (cf. A Fast String Searching Algorithm, with R.S. Boyer.  Communications
+# of the Association for Computing Machinery, 20(10), 1977, pp. 762-772.)
+# http://www.cs.utexas.edu/users/moore/best-ideas/string-searching/index.html
 class BM_Pattern
-special Pattern 
-       redef meth to_s do return _motif
+       super Pattern
 
-       # boyer-moore search gives the position of the first occurence of a pattern starting at position `from'
-       redef meth search_index_in(s, from)
+       redef fun to_s do return _motif
+
+       # boyer-moore search gives the position of the first occurrence of a pattern starting at position `from'
+       redef fun search_index_in(s, from)
        do
                assert from >= 0
                var n = s.length
@@ -77,7 +77,7 @@ special Pattern
                while j < n - m + 1 do
                        var i = m - 1 # Cursor in the pattern
                        while i >= 0 and _motif[i] == s[i + j] do i -= 1
-                       if (i < 0) then
+                       if i < 0 then
                                return j
                        else
                                var gs = _gs[i] # Good shift
@@ -94,7 +94,7 @@ special Pattern
        end
 
        # boyer-moore search. Return null if not found 
-       redef meth search_in(s, from)
+       redef fun search_in(s, from)
        do
                var to = search_index_in(s, from)
                if to < 0 then
@@ -116,12 +116,12 @@ special Pattern
        end
 
        # searched motif
-       attr _motif: String
+       var _motif: String
 
        # length of the motif
-       attr _length: Int
+       var _length: Int
 
-       private meth bc(e: Char): Int
+       private fun bc(e: Char): Int
        do 
                if _bc_table.has_key(e) then
                        return _bc_table[e]
@@ -131,12 +131,12 @@ special Pattern
        end
 
        # good shifts
-       attr _gs: Array[Int]
+       var _gs: Array[Int]
        
        # bad characters
-       attr _bc_table: Map[Char, Int]
+       var _bc_table: Map[Char, Int]
 
-       private meth compute_bc
+       private fun compute_bc
        do
                var x = _motif
                var m = _length
@@ -147,13 +147,13 @@ special Pattern
                end
        end
 
-       private meth suffixes: Array[Int]
+       private fun suffixes: Array[Int]
        do
                var x = _motif
                var m = _length
                var suff = new Array[Int].filled_with(m, m)
 
-               var f: Int
+               var f = 0
                var g = m - 1
                var i = m - 2
                while i >= 0 do
@@ -170,7 +170,7 @@ special Pattern
                return suff
        end
 
-       private meth compute_gs
+       private fun compute_gs
        do
                var x = _motif
                var m = _length
@@ -202,25 +202,24 @@ end
 # Matches are a part of a string.
 class Match
        # The base string matched
-       readable attr _string: String
+       readable var _string: String
 
        # The starting position in the string
-       readable attr _from: Int
+       readable var _from: Int
 
-       # The length of the mathching part
-       readable attr _length: Int
+       # The length of the matching part
+       readable var _length: Int
 
        # The position of the first character just after the matching part.
        # May be out of the base string
-       meth after: Int do return _from + _length
+       fun after: Int do return _from + _length
 
-       # The contents of the mathing part
-       redef meth to_s do return _string.substring(_from, _length)
+       # The contents of the matching part
+       redef fun to_s do return _string.substring(_from, _length)
 
        # Matches `len' characters of `s' from `f'.
        init(s: String, f: Int, len: Int)
        do
-               assert non_null_string: s != null 
                assert positive_length: len >= 0
                assert valid_from: f >= 0
                assert valid_after: f + len <= s.length
@@ -231,8 +230,9 @@ class Match
 end
 
 redef class Char
-special Pattern
-       redef meth search_index_in(s, from)
+       super Pattern
+
+       redef fun search_index_in(s, from)
        do
                var stop = s.length
                while from < stop do
@@ -242,7 +242,7 @@ special Pattern
                return -1
        end
 
-       redef meth search_in(s, from)
+       redef fun search_in(s, from)
        do
                var pos = search_index_in(s, from)
                if pos < 0 then
@@ -254,8 +254,9 @@ special Pattern
 end
 
 redef class String
-special Pattern
-       redef meth search_index_in(s, from)
+       super Pattern
+
+       redef fun search_index_in(s, from)
        do
                assert from >= 0
                var stop = s.length - length + 1
@@ -270,7 +271,7 @@ special Pattern
                return -1
        end
 
-       redef meth search_in(s, from)
+       redef fun search_in(s, from)
        do
                var pos = search_index_in(s, from)
                if pos < 0 then
@@ -280,26 +281,26 @@ special Pattern
                end
        end
 
-       # Like `search_from' but from the first chararter.
-       meth search(p: Pattern): Match do return p.search_in(self, 0)
+       # Like `search_from' but from the first character.
+       fun search(p: Pattern): nullable Match do return p.search_in(self, 0)
 
        # Search the given pattern into self from a.
        # The search starts at `from'.
        # Return null if not found.
-       meth search_from(p: Pattern, from: Int): Match do return p.search_in(self, from)
+       fun search_from(p: Pattern, from: Int): nullable Match do return p.search_in(self, from)
 
-       # Search all occurences of p into self.
+       # Search all occurrences of p into self.
        #
        #   var a = new Array[Int]
        #   for i in "hello world".searches('o') do
        #       a.add(i.from)
        #   end
        #   a    # -> [4, 7]
-       meth search_all(p: Pattern): Array[Match] do return p.search_all_in(self)
+       fun search_all(p: Pattern): Array[Match] do return p.search_all_in(self)
 
-       # Split self using p is separator.
+       # Split `self` using `p` as separator.
        #   "hello world".split('o')     # -> ["hell", " w", "rld"]
-       meth split_with(p: Pattern): Array[String]
+       fun split(p: Pattern): Array[String]
        do
                var matches = p.split_in(self)
                var res = new Array[String].with_capacity(matches.length)
@@ -307,7 +308,28 @@ special Pattern
                return res
        end
 
-       # Split self using '\n' is separator.
-       #   "hello\nworld".split     # -> ["hello","world"]
-       meth split: Array[String] do return split_with('\n')
+       # @deprecated alias for `split`
+       fun split_with(p: Pattern): Array[String] do return self.split(p)
+
+       # Replace all occurences of a pattern with a string
+       #
+       #   "hlelo".replace("le", "el") # -> "hello"
+       #   "hello".replace('l', "")    # -> "heo"
+       fun replace(p: Pattern, string: String): String
+       do
+               return self.split_with(p).join(string)
+       end
+
+       # Escape the four characters < > & and " with their html counterpart
+       #
+       #    "a&b->\"x\"".html_escape # -> "a&amp;b-&gt;&quot;x&quot;"
+       fun html_escape: String
+       do
+               var ret = self
+               if ret.has('&') then ret = ret.replace('&', "&amp;")
+               if ret.has('<') then ret = ret.replace('<', "&lt;")
+               if ret.has('>') then ret = ret.replace('>', "&gt;")
+               if ret.has('"') then ret = ret.replace('"', "&quot;")
+               return ret
+       end
 end