File: xstr_search.ml

package info (click to toggle)
xstr 0.2.1-25
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 256 kB
  • sloc: ml: 1,069; makefile: 82; sh: 1
file content (202 lines) | stat: -rw-r--r-- 4,377 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
(* $Id: xstr_search.ml,v 1.1 1999/06/27 23:03:38 gerd Exp $
 * ----------------------------------------------------------------------
 * Search & Replace
 *)


exception Replace_phrase of (int * string);;


let index_of_substring_from s k_left substr =
  let l = String.length s in
  let lsub = String.length substr in
  let k_right = l - lsub in
  let c = if substr <> "" then substr.[0] else ' ' in
  let rec search k =
    if k <= k_right then begin
      if String.sub s k lsub = substr then
	k
      else
	let k_next = String.index_from s (k+1) c in
	search k_next
    end
    else raise Not_found
  in
  if substr = "" then k_left else search k_left
;;


let rindex_of_substring_from s k_right substr =
  let lsub = String.length substr in
  let c = if substr <> "" then substr.[0] else ' ' in
  let rec search k =
    if k >= 0 then begin
      if String.sub s k lsub = substr then
	k
      else
	let k_next = String.rindex_from s (k-1) c in
	search k_next
    end
    else raise Not_found
  in
  if substr = "" then k_right else search k_right
;;


let index_of_substring s substr =
  index_of_substring_from s 0 substr;;

let rindex_of_substring s substr =
  rindex_of_substring_from s (String.length s - String.length substr) substr;;


let contains_substring s substr =
  try
    let _ = index_of_substring s substr in true
  with
    Not_found -> false
;;


let contains_substring_from s k_left substr = 
  try
    let _ = index_of_substring_from s k_left substr in true
  with
    Not_found -> false
;;


let rcontains_substring_from s k_right substr = 
  try
    let _ = rindex_of_substring_from s k_right substr in true
  with
    Not_found -> false
;;


let indexlist_of_substring s substr =
  let rec enumerate k =
    try
      let pos = index_of_substring_from s k substr in
      pos :: enumerate (pos+1)
    with
      Not_found -> []
  in
  enumerate 0
;;


let rev_concat sep sl =
  (* = String.concat sep (List.rev sl), but more efficient *)

  let lsep = String.length sep in
  let rec get_len v sl =
    match sl with
      [] -> v
    | s :: sl' ->
	get_len (v + lsep + String.length s) sl'
  in

  let len = 
    if sl = [] then 0 else get_len 0 sl - lsep in

  let t = Bytes.create len in
  
  let rec fill_in k sl =
    match sl with
      [] -> ()
    | [ s ] ->
	let s_len = String.length s in
	String.blit s 0 t (k-s_len) s_len
    | s :: sl' ->
	let s_len = String.length s in
	let k' = k - s_len in
	let k'' = k' - lsep in
	String.blit s 0 t k' s_len;
	String.blit sep 0 t k'' lsep;
	fill_in k'' sl'
  in

  fill_in len sl;
  Bytes.to_string t
;;


let replace_char s rule =
  let l = String.length s in
  let rec replace coll k_last k =
    if k < l then begin
      let c = s.[k] in
      try
	let s' = rule c k in
	raise (Replace_phrase (1,s'))
	  (* Alternatively, we could directly invoke 'replace' with some
	   * parameters. But this would be a true recursion, without the
	   * chance to be eliminated.
	   * Would lead to Stack_overflow for large strings.
	   *)
      with
	Match_failure(_,_,_) ->
	  replace coll k_last (k+1)
      |	Not_found ->
	  replace coll k_last (k+1)
      |	Replace_phrase (length, s') ->
	  replace (s' :: String.sub s k_last (k-k_last) :: coll) (k+length) (k+length)
    end
    else
      String.sub s k_last (k-k_last) :: coll
  in
  rev_concat "" (replace [] 0 0)
;;


let replace_substring s substrlist rule =
  let characters =
      (List.map
	 (fun substr ->
	   if substr = "" then
	     failwith "replace_substring"
	   else
	     substr.[0])
	 substrlist) in

  let l = String.length s in

  let rec find k sl =
    match sl with
      [] -> raise Not_found
    | sub :: sl' ->
	let lsub = String.length sub in
	if k <= l - lsub && String.sub s k lsub = sub then
	  let replacement = rule sub k in
	  raise (Replace_phrase(lsub, replacement))
	else
	  raise Not_found
  in

  let rule' c k =
    if List.mem c characters then 
      find k substrlist
    else
      raise Not_found
  in

  let rule'' c0 c k =
    if c = c0 then find k substrlist else raise Not_found in

  if List.length substrlist = 1 then
    replace_char s (rule'' (List.hd substrlist).[0])
  else
    replace_char s rule'
;;


(* ======================================================================
 * History:
 * 
 * $Log: xstr_search.ml,v $
 * Revision 1.1  1999/06/27 23:03:38  gerd
 * 	Initial revision.
 *
 * 
 *)