class String
FEATURES TODO NEXT REVISION ##
1: to_morse (maybe … limited appeal my guess) 2: encryption? (maybe a separate gem, or include a wrapper from that gem) 3: format number to engineering notation … 15530.to_eng => 1515.53e3
Constants
- GS_SENTENCE_TERM
- GS_TITLE_EXCEPTIONS
- RGX_FLOAT
- ROT_LEN
- ROT_STRING
ROT_STRING
= ‘ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789?/>.<,“':;|\}]{[+=_-)(*&^%$#@!`~Ω≈ç√∫˜µ≤≥÷åß∂ƒ©˙∆˚¬…æœ∑´®†¥¨ˆøπ“‘«`¡™£¢∞§¶•ªº–≠¸˛Ç◊ı˜Â¯˘¿ÅÍÎÏ˝ÓÔÒÚÆŒ„´‰ˇÁ¨ˆØ∏”’»`⁄€‹›fifl‡°·‚—±’- R_RATED
- SET_CHARS
- SET_COMPACT_LEFT
- SET_COMPACT_RIGHT
- SET_INT_CHARS
- SET_LIKE_KEEP
- SET_LOWERS
- SET_PARSE_CHARS
- SET_SPLIT_CHARS
- SET_SUB_CHARS
- SET_SUP_CHARS
- SET_UPPERS
- SET_VERTICLE
- SI_UNIT_PREFIXES
- STD_ESCAPE_HASH
- STD_ESCAPE_SET_RUBY
Public Class Methods
# File lib/gstring.rb, line 119 def self.chr_uni_esc(num) num = num.to_i return nil if num < 0 if num < 256 rtn = "\\x" + num.to_s(16).padto(2,'0',:left) elsif num < 0x10000 rtn = "\\u" + num.to_s(16).padto(4,'0',:left) elsif num < 0x1000000 rtn = "\\u" + num.to_s(16).padto(6,'0',:left) else rtn = "\\u" + num.to_s(16).padto(8,'0',:left) end end
# File lib/gstring.rb, line 75 def self.define_bracket_pair(str) @@gs_bracketing_pairs[str.first] = str.last end
ary.sort &String::inside_int_cmp
# File lib/gstring.rb, line 80 def self.inside_int_cmp(mode=true) return lambda do |a,b| a,b = (mode) ? [a.to_s, b.to_s] : [b.to_s, a.to_s] if(a==b) 0 else ta = a.dup tb = b.dup rgx = /\d+/ if (ta.find(rgx).nil? || tb.find(rgx).nil?) a <=> b # standard compare else # int inside one or both rtn=0 loop do if(ta==tb) rtn=0 break end if(ta.empty? || tb.empty?) rtn = ta <=> tb break end la = ta.parse(rgx, :no_skip, :no_strip) lb = tb.parse(rgx, :no_skip, :no_strip) if(la != lb) rtn = la <=> lb break end if(ta.parsed != tb.parsed) rtn = ta.parsed.to_i <=> tb.parsed.to_i break end end #loop rtn end # if end # if end # lambda end
generator does not need an instance
# File lib/gstring.rb, line 581 def self.random_password(chars=8, special="_-#!~@$%^*+=?:") raise "password must be at least 8 characters" if chars < 8 low = BitSet.lowercase_chars high = BitSet.uppercase_chars digits = BitSet.digit_chars special = special.to_bset rescue BitSet.new all = low | high | digits | special a,b = low.rand(2,:array_chars) c,d = high.rand(2, :array_chars) e = digits.rand(1, :array_chars) f = special.rand(1, :array_chars) pswd = [a,b,c,d,e] pswd.push f unless (f.nil? || f.empty?) filler = all.rand(chars - pswd.length, :array_chars) filler.each do |ch| pswd.push ch end pswd.shuffle! return pswd.join '' end
# File lib/gstring.rb, line 61 def self.reset_bracket_pairs @@gs_bracketing_pairs = { '[' => ']', '(' => ')', '{' => '}', '<' => '>' } end
# File lib/gstring.rb, line 71 def self.undefine_bracket_pair(str) @@gs_bracketing_pairs.delete(str.first) end
Public Instance Methods
default char for blank? or new mode
# File lib/gstring.rb, line 1644 def access_mode(md=:stop, dflt=' ') # :swing :stick :default :rotate @gs_access_mode = md @gs_default_str = dflt @gs_np_pos = nil @gs_dir = :up self end
# File lib/gstring.rb, line 1103 def append(*prms) rtn = "" prms.each do |item| rtn += item.to_s end self + rtn end
# File lib/gstring.rb, line 1111 def append!(*prms) replace self.append(*prms) end
non-alpha chars must match too
# File lib/gstring.rb, line 224 def case_match(other) # true if string same size with same case at all positions return false if (length != other.length) length.times do |idx| if (self[idx].upcase?) return false unless other[idx].upcase? elsif (self[idx].downcase?) return false unless other[idx].downcase? else # both must be letters at the position return false if self[idx] != other[idx] end end return true end
# File lib/gstring.rb, line 199 def clean?(rgx = R_RATED) return self.scan(rgx).empty? end
replace with this …
# File lib/gstring.rb, line 564 def cmp(other) self <=> other end
# File lib/gstring.rb, line 568 def cmpi(other) self.upcase <=> other.upcase end
# File lib/gstring.rb, line 1450 def compact(sl=SET_COMPACT_LEFT, sr=SET_COMPACT_RIGHT) #sl = sl.to_bset #sr = sr.to_bset rtn = "" state = :start each_char do |ch| if :start == state next if ch <= ' ' state = state = sr.include?(ch) ? :right : :add rtn += ch elsif :add == state if ch <= ' ' state = :zap rtn += ' ' elsif sr.include? ch state = :right rtn += ch else rtn += ch end elsif :right == state unless ch <= ' ' rtn += ch state = sr.include?(ch) ? :right : :add end else #elsif :zap == state next if ch <= ' ' rtn.pop if sl.include? ch # state = :add state = sr.include?(ch) ? :right : :add rtn += ch end end rtn.pop if rtn.last==' ' return rtn end
# File lib/gstring.rb, line 1488 def compact!(sl=SET_COMPACT_LEFT, sr=SET_COMPACT_RIGHT) replace compact(sl, sr) end
# File lib/gstring.rb, line 409 def condense dup.condense! end
# File lib/gstring.rb, line 393 def condense! strip! str = "" sp = false each_char do |ch| if (ch <= ' ') sp = true else str += sp ? ' ' + ch : ch sp = false end end replace str self end
# File lib/gstring.rb, line 345 def cross_match(pat) s_ptr=0 p_ptr=0 ch = '' return nil unless pat.class==String return false if empty? return false if pat.empty? loop do return true if s_ptr >= self.length return false if p_ptr >= pat.length if ch != '' if ch==self[s_ptr] ch="" s_ptr +=1 p_ptr +=1 if s_ptr >= self.length return false if pat[p_ptr]=='+' end else s_ptr +=1 return false if s_ptr >= self.length # ran out before match end elsif (pat[p_ptr]=='_') p_ptr+=1 s_ptr+=1 elsif (pat[p_ptr]=='+') s_ptr+=1 # skip next letter p_ptr+=1 ch = pat[p_ptr] return true if (ch.nil? || ch=='') #end of the line elsif (pat[p_ptr]=='*') p_ptr+=1 ch = pat[p_ptr] return true if (ch.nil? || ch=='') #end of the line elsif (pat[p_ptr]=='`') p_ptr+=1 return false unless pat[p_ptr]==self[s_ptr] p_ptr+=1 s_ptr+=1 else # compare chars return false unless pat[p_ptr]==self[s_ptr] p_ptr+=1 s_ptr+=1 end end return true end
# File lib/gstring.rb, line 304 def cryptogram(dat=nil) # nil==> encode, string==>test for match if (dat.nil?) rtn = dup set = BitSet.lowercase_chars off_limits = [] skey = nil ary = (self.downcase.to_bset & String::SET_LOWERS).to_a(false).shuffle loop do break if ary.empty? skey = ary.pop hits = find_all(skey,:ignore) - off_limits off_limits = (off_limits | hits).sort # edge case, set only has 1 element in it rpw = (set.count==1) ? set.to_s : (set - skey).rand(1,:string) set -= rpw #can only use an element once hits.each do |pos| rtn.swapchar(pos, rpw, :casehold) end end return rtn elsif (dat.class==String) return false if self.length != dat.length s1 = self.downcase.to_bset & BitSet.lowercase_chars s2 = dat.downcase.to_bset & BitSet.lowercase_chars return false if s1.count != s2.count ary1 = self.downcase.find_all(s1) ary2 = dat.downcase.find_all(s2) return false if ary1 != ary2 return false unless case_match(dat) length.times do |idx| # ::TODO:: find faster way ... ary1 = self.find_all(self[idx],:ignore) ary2 = dat.find_all(dat[idx],:ignore) return false if ary1 != ary2 end return true else return nil end nil end
# File lib/gstring.rb, line 1080 def dec(val=nil) return dup.dec!(val) end
# File lib/gstring.rb, line 1070 def dec!(val=nil) num = extract_trailing_int! return self if num.nil? return self if 0==num val ||= 1 return self if (num-val) < 0 append!(num-val) dup end
# File lib/gstring.rb, line 210 def downcase? set = self.to_bset return false if String::SET_UPPERS ** set # may not have any lower return nil unless String::SET_LOWERS ** set # must have at least one lower return true end
# File lib/gstring.rb, line 452 def duplicates str = self.sort set = BitSet.new rtn = "" last_chr = "" str.each_char do |ch| if last_chr == ch unless set.include? ch rtn += ch end set.add! ch end last_chr = ch end return rtn end
# File lib/gstring.rb, line 446 def duplicates? set = self.to_bset return false if set.count == length return true end
# File lib/gstring.rb, line 480 def each_ord unless block_given? enu = Enumerator.new do |y| self.each_char do |ch| y << ch.ord end end return enu end self.each_char do |ch| yield ch.ord end end
# File lib/gstring.rb, line 712 def enclose(pairs, escape=nil, set=String::STD_ESCAPE_SET_RUBY, hash=String::STD_ESCAPE_HASH) return self if pairs.empty? if escape.nil? return pairs.first + self + pairs.last else # look for pairs.first , and replace with {escape}{pairs.first} str = pairs.first self.each_char do |ch| if set.include? ch idx = (set & ch).to_a.first if (ch ** (set-[0..31])) #byebug str += "\\" + ch elsif hash.include? idx #byebug str += hash[idx] else # use hex format str += String.chr_uni_esc(idx) end else str += ch end end return str + pairs.last #str = self.gsub(pairs.first) { escape + pairs.first } #return pairs.first + str + pairs.last end end
# File lib/gstring.rb, line 740 def enclose!(pairs, escape=nil) replace enclose(pairs, escape) end
# File lib/gstring.rb, line 572 def eqli?(other) self.upcase == other.upcase end
# File lib/gstring.rb, line 576 def equali?(other) self.upcase == other.upcase end
# File lib/gstring.rb, line 708 def extract(prm) return dup.extract!(prm, '') end
# File lib/gstring.rb, line 635 def extract!(prm=1, fill_hole="") return "" if empty? if prm.kind_of? Integer # extract fron-end of string return "" if prm < 1 prm = prm > length ? length : prm rtn = self[0..(prm-1)] # replace( fill_hole + self[prm..-1] ) # WRONG! ... we only want the same number of fill replace( fill_hole[0..(prm-1)] + self[prm..-1] ) return rtn elsif prm.class == Range start = prm.first < 0 ? self.length + prm.first : prm.first finish = prm.last < 0 ? self.length + prm.last : prm.last if (start <= finish) # normal forward order return "" if start >= length finish = finish >= length ? length-1 : finish return extract!(finish+1, fill_hole) if start==0 # was extract without the '!' rtn = self[start..finish] replace(self[0..(start-1)] + fill_hole + self[(finish+1)..-1]) return rtn else # reverse order return "" if finish >= length start = start >= length ? length - 1 : start rtn = self[finish..start].reverse if(finish==0) replace(fill_hole + self[(start+1)..-1]) else replace(self[0..(finish-1)] + fill_hole + self[(start+1)..-1]) end return rtn end elsif prm.class == Array rtn = "" # first count number of substitutions cnt = 0 prm.each do |item| if item.kind_of? Integer cnt += 1 else cnt += item.count end end filler = fill_hole.padto(cnt, "\000", :right, :no_trunc) # use null as place holder prm.each do |item| if item.kind_of? Integer pos = item < 0 ? 0 : item if pos < length rtn += self[pos] self[pos]=filler.first! end # ignore if out of range else # use recursion str = self.extract!(item, filler) rtn += str filler.extract! str.length # remove and discard end end remove! "\000".to_bset return rtn else # convert to set ary = (prm.to_bset & (0..(self.length-1))).to_a #ignore everything out of range fill=fill_hole.dup rtn = "" oft = 0 ary.each do |idx| ch = fill.extract! rtn += self[idx-oft] self[idx-oft]=ch oft+=1 if ch.empty? end return rtn end return "" end
# File lib/gstring.rb, line 1123 def extract_leading_set!(set) rtn = "" set = set.to_bset while set.include? first do rtn += first! end return rtn end
# File lib/gstring.rb, line 1375 def extract_num! dat = parse(String::RGX_FLOAT, :no_skip) if parsed.nil? # no number found num = dat.extract_leading_set!(BitSet.digit_chars) replace dat return 0 if num.empty? return num.to_i else return parsed.to_f end end
# File lib/gstring.rb, line 1059 def extract_trailing_int! return nil if empty? return nil unless String::SET_INT_CHARS.include? last str = "" while String::SET_INT_CHARS.include? last str += last! break if empty? end return str.reverse.to_i end
# File lib/gstring.rb, line 1132 def extract_trailing_set!(set) rtn = "" set = set.to_bset while set.include? last do rtn += last! end return rtn.reverse end
# File lib/gstring.rb, line 262 def find_all(obj, *modes) # returns an array of all positions of obj in self pos = 0 ary = [] loop do pos = self.index(obj, pos, *modes) break if pos.nil? ary.push pos pos +=1 end return ary end
# File lib/gstring.rb, line 274 def find_near(pos, obj=String::SET_SPLIT_CHARS, *flags) p_r = self.index(obj, pos, *flags) p_l = self.rindex(obj, pos, *flags) return [p_l,p_r] end
# File lib/gstring.rb, line 280 def find_nth(obj, nth, *modes) return nil if 0==nth if nth > 0 pos = 0 loop do nth -= 1 pos = self.index(obj, pos, *modes) return nil if pos.nil? return pos if nth.zero? pos += 1 end else nth = -nth pos = length loop do nth -= 1 pos = self.rindex(obj, pos, *modes) return nil if pos.nil? return pos if nth.zero? pos -= 1 end end end
# File lib/gstring.rb, line 1028 def first return "" if empty? self[0] end
removes first char
# File lib/gstring.rb, line 1039 def first! return "" if empty? rtn = self[0] replace self[1..(length-1)] return rtn end
# File lib/gstring.rb, line 1163 def gs_titlecase downcase! if index(GS_SENTENCE_TERM) ary = self.split_on_set(GS_SENTENCE_TERM) pa = [] ary.first.each do |sentence| pa.push(sentence.gs_titlecase.strip) end ary[0] = pa.reverse! ary[1].reverse! rtn = ary.first.pop until ary.first.empty? rtn += "#{ary[1].pop} #{ary.first.pop}" end rtn += ary.last || "" return rtn end ary = self.split(' ') ary.first.capitalize! ary.last.capitalize! (1..(ary.size-2)).each do |idx| ary[idx].capitalize! unless GS_TITLE_EXCEPTIONS.include?(ary[idx]) end return ary.join ' ' end
# File lib/gstring.rb, line 1189 def gs_titlecase! replace gs_titlecase end
# File lib/gstring.rb, line 438 def histogram hash = {} self.split('').sort.each do |ch| hash[ch] = hash[ch].nil? ? 1 : 1 + hash[ch] end return hash end
# File lib/gstring.rb, line 854 def ignore_me self end
# File lib/gstring.rb, line 1099 def inc(val=nil) return dup.inc!(val) end
increments integer at end of string
# File lib/gstring.rb, line 1085 def inc!(val=nil) num = extract_trailing_int! if num.nil? if val.nil? append!(0) else append!(val) end else append! (val.nil? ? (num+1) : (num+val)) end dup end
# File lib/gstring.rb, line 765 def indent cnt = 0 each_char do |ch| break if ch > ' ' cnt += 1 end cnt end
# File lib/gstring.rb, line 774 def indent! rtn = indent lstrip! return rtn end
# File lib/gstring.rb, line 948 def index(search,from=0,*options) while options.first.class==Array options = options.first end if (search.class==String) return self.downcase.index(search.downcase,from) if (options.include? :ignore) return old_string_index_method_4gstring(search,from) end if search.class==Array best = nil search.each_with_index do |item,idx| pos = index(item,from,options) unless pos.nil? @best ||= idx best ||= pos if pos < best best = pos @best = idx end end end return best # parse uses this to know which item was found end # call this for unrecognized options return old_string_index_method_4gstring(search,from) unless search.class == BitSet if options.include? :ignore return self.downcase.index(search.add_opposing_case,from) end if (from < 0) from = length + from end from = 0 if from < 0 ((from)...(length)).each do |ptr| return ptr if search.include? self[ptr] end return nil end
# File lib/gstring.rb, line 623 def keep(ks) # only keep chars belonging to set rtn = "" self.each_char do |ch| rtn += ch if ks.include? ch end return rtn end
# File lib/gstring.rb, line 631 def keep!(ks) replace keep(ks) end
# File lib/gstring.rb, line 1033 def last return "" if empty? self[length-1] end
removes last char
# File lib/gstring.rb, line 1047 def last! if length==1 rtn = dup self.clear return rtn end return "" if empty? rtn = self[length-1] replace self[0..(length-2)] return rtn end
# File lib/gstring.rb, line 173 def like(table_class_name, table_column_name, mode_and=true, kp = SET_LIKE_KEEP) ary = [] self.split.each do |substr| str = substr.keep kp if (str.first=='*') str.first! if (str.last=='*') str.last! ary.push "%#{str}%".gsub('*', '%') else ary.push "%#{str}".gsub('*', '%') end elsif (str.last=='*') str.last! ary.push "#{str}%".gsub('*', '%') else ary.push "%#{str}%".gsub('*', '%') end end #each md = mode_and ? ' and ' : ' or ' qry = (["`#{table_column_name}` like ?"] * ary.count).join md return table_class_name.where(qry, *ary) end
# File lib/gstring.rb, line 1563 def limit_to(size, *flags) size = length + size + 1 if size < 0 if flags.first.kind_of? Integer flags=flags.dup cnt=flags.reverse!.pop pos = find_nth(SET_VERTICLE,cnt,*flags) if pos && (pos < size) size = pos + 1 end end return self if length <= size if flags.include? :no_break pos = self.rfind(SET_SPLIT_CHARS,size-1) return self[0..(size-2)] + '…' if pos.nil? return self[0..(pos-1)] + '…' else return self[0..(size-2)] + '…' end end
# File lib/gstring.rb, line 1583 def limit_to!(size, *flags) replace limit_to(size, *flags) end
# File lib/gstring.rb, line 217 def mixedcase? set = self.to_bset return nil unless set ** (String::SET_LOWERS | String::SET_UPPERS) # must have a letter return (set ** String::SET_LOWERS) && (set ** String::SET_UPPERS) end
# File lib/gstring.rb, line 1652 def next @gs_np_pos ||= nil @gs_access_mode ||= :stop @gs_dir ||= :up return "" if empty? if @gs_np_pos.nil? ch = first @gs_np_pos = 0 return ch else case @gs_access_mode when :stop @gs_np_pos = @gs_np_pos >= length ? length : @gs_np_pos + 1 ch = self[@gs_np_pos] return ch.nil? ? "" : ch when :rotate @gs_np_pos += 1 @gs_np_pos = @gs_np_pos >= length ? 0 : @gs_np_pos return self[@gs_np_pos] when :stick @gs_np_pos = @gs_np_pos >= length ? length : @gs_np_pos + 1 ch = self[@gs_np_pos] return ch.nil? ? last : ch when :default @gs_np_pos = @gs_np_pos >= length ? length : @gs_np_pos + 1 ch = self[@gs_np_pos] return ch.nil? ? @gs_default_str : ch when :swing return first if length==1 if @gs_dir== :up @gs_np_pos += 1 if @gs_np_pos >= length @gs_dir= :down @gs_np_pos = length - 2 end return self[@gs_np_pos] else # :down @gs_np_pos -= 1 if @gs_np_pos < 0 @gs_dir= :up @gs_np_pos = 1 end return self[@gs_np_pos] end else raise "unsupported access mode" end end end
##
Updates to existing index, rindex methods # now accepts search types of: Set, Array #
##
- ::todo
-
Add flags :rotate, :stick
# File lib/gstring.rb, line 782 def padto(tar, *prms) return self if length == tar prms = prms.first if prms.first.kind_of? Array with = ' ' flags = [] how = :left prms.each do |prm| if prm.kind_of? String with=prm next end case prm when :no_trunc, :rotate, :stick, :space, :swing flags.push prm when :left, :right, :both how = prm else raise "padto unknown parameter" end end if length > tar return self if flags.include? :no_trunc return "" if tar<=0 return '…' if tar==1 return self[0..(tar-2)]+'…' end with = ' ' if with.empty? rtn = "" flags -= [:no_trunc] flag = flags.empty? ? :stick : flags.first with.access_mode(flag==:space ? :default : flag) case how when :right rtn = self (tar-length).times do |xx| rtn += with.next end when :both lp = (tar-length) >> 1 rp = (tar-length) - lp str = "" (rp).times do |xx| str += with.next end rtn = str[0..(lp-1)].reverse + self + str else # :left str = "" (tar-length).times do |xx| str += with.next end rtn += str.reverse + self end rtn end
# File lib/gstring.rb, line 837 def padto!(tar, *flags) replace padto(tar, flags) end
# File lib/gstring.rb, line 858 def parse(search_key = String::SET_PARSE_CHARS, *options) options = options.first if options.first.class==Array meth = options.include?(:no_strip) ? :ignore_me : :strip rtn="" @found = nil if(search_key.class==BitSet) #skip over first char idx = options.include?(:no_skip) ? 0 : 1 sk = options.include?(:ignore) ? search_key.add_opposing_case : search_key sf = idx self[sf...length].each_char do |ch| if(sk.include? ch) @found=ch break end idx += 1 end unless @found.nil? rtn = (idx==0) ? "" : self[0..(idx-1)].send(meth) replace self[(idx+1)..-1].send(meth) return rtn end rtn = clone clear return rtn elsif (search_key.class == Regexp) sf = options.include?(:no_skip) ? 0 : 1 pos = index(search_key,sf) @found = pos.nil? ? nil : self.match(search_key)[0] if pos.nil? rtn = clone clear return rtn else # found rtn = pos.zero? ? "" : self[0..(pos-1)].send(meth) replace self[(pos+@found.length)..length].send(meth) return rtn end elsif (search_key.class == String) #skip over first char unless option specifies :no_skip sf = options.include?(:no_skip) ? 0 : 1 idx = index(search_key,sf,options) if idx.nil? rtn = clone clear return rtn else rtn = idx.zero? ? "" : self[0..(idx-1)].send(meth) @found = self[idx..(idx+search_key.length-1)] replace self[(idx+search_key.length)..length].send(meth) return rtn end elsif (search_key.class == Array) shortest = nil best = nil start = options.include?(:no_skip) ? 0 : 1 search_key.each_with_index do |val,idx| pos = self.index(val,start,options) unless pos.nil? best = idx if best.nil? shortest ||= pos if (pos < shortest) shortest = pos best = idx end end end if shortest.nil? rtn = clone clear return rtn else #opt = options.dup #opt[:no_skip]=true #return parse(search_key[best],opt) return parse(search_key[best],options) end else # we are passed something that should have been converted to a set return parse([search_key].to_bset,options) end end
# File lib/gstring.rb, line 1119 def parsed @found ||= nil end
negative len means position from right to left positive len means number of chars to capture exception if pos and len are both negative and pos > len … then starting point is the |sum| from the right, and length … and the ending point is also the |sum| ??? need more examples
# File lib/gstring.rb, line 846 def php_substr(pos=0,len=nil) return "" if len==0 len = len.nil? ? length : len r_s = (pos >= 0) ? pos : pos + length r_e = (len >= 0) ? r_s + len - 1 : len + length - 1 return self[(r_s)..(r_e)] end
# File lib/gstring.rb, line 417 def pop(nchars=1) if (nchars < 1) # avoid silly requests return "" elsif (nchars >= length) rtn = dup replace "" return rtn end rtn = self[-nchars..-1] replace self[0..(length-nchars-1)] return rtn end
# File lib/gstring.rb, line 1702 def prev @gs_np_pos ||= nil @gs_access_mode ||= :stop @gs_dir ||= :up return "" if empty? if @gs_np_pos.nil? ch = last @gs_np_pos = length - 1 return ch else case @gs_access_mode when :stop @gs_np_pos = @gs_np_pos <= 0 ? -1 : @gs_np_pos - 1 return "" if @gs_np_pos < 0 return self[@gs_np_pos] when :rotate @gs_np_pos -= 1 @gs_np_pos = @gs_np_pos < 0 ? length-1 : @gs_np_pos return self[@gs_np_pos] when :stick @gs_np_pos = @gs_np_pos <= 0 ? -1 : @gs_np_pos - 1 return first if @gs_np_pos < 0 return self[@gs_np_pos] when :default @gs_np_pos = @gs_np_pos <= 0 ? -1 : @gs_np_pos - 1 return @gs_default_str if @gs_np_pos < 0 return self[@gs_np_pos] when :swing return first if length==1 if @gs_dir== :down @gs_np_pos += 1 if @gs_np_pos >= length @gs_dir= :up @gs_np_pos = length - 2 end return self[@gs_np_pos] else # :up @gs_np_pos -= 1 if @gs_np_pos < 0 @gs_dir= :down @gs_np_pos = 1 end return self[@gs_np_pos] end else raise "unsupported access mode" end end end
# File lib/gstring.rb, line 413 def push(str) replace(self+str).dup end
# File lib/gstring.rb, line 1603 def rand(cnt=1, *prms) return "" if empty? return "" if cnt < 1 if length==1 return self if prms.include? :set return self * cnt end rnd = Random.new rtn = "" str = prms.include?(:set) ? self.to_bset.to_s : self.dup cnt.times do break if str.empty? ch = str[rnd.rand(str.length)] rtn += ch str[str.find(ch)] = "" if prms.include? :once end return rtn end
# File lib/gstring.rb, line 1622 def rand!(cnt=1, *prms) # once is implied return "" if empty? return "" if cnt < 1 if length==1 return first! end rnd = Random.new rtn = "" cnt.times do break if self.empty? ch = self[rnd.rand(self.length)] rtn += ch if prms.include? :set remove! ch.to_bset else self[self.find(ch)] = "" end end return rtn end
# File lib/gstring.rb, line 494 def rehash # more consistent hash method sum = 0 tr = 4294967296 rL = Random.new(self.length) sum = rL.rand(tr) self.each_char do |ch| rt = Random.new(ch.ord) sum += rt.rand(tr) sum ^= rL.rand(sum) end return sum & (tr-1) end
# File lib/gstring.rb, line 617 def remove(obj, *prm) # remove all characters str = dup str.remove!(obj, *prm) return str end
# File lib/gstring.rb, line 602 def remove!(obj, *prm) # remove all characters flags = prm.dup flags |= [:no_skip, :no_strip] rtn = "" str = "" loop do str += parse(obj,flags) break if parsed.nil? rtn += parsed end str += self replace str return rtn end
# File lib/gstring.rb, line 988 def rindex(search,from=-1,*options) options = options.first if options.first.class==Array if (search.class==String) return self.downcase.rindex(search.downcase,from) if (options.include? :ignore) return old_string_rindex_method_4gstring(search,from) end if search.class==Array best = nil search.each_with_index do |item,idx| pos = rindex(item,from,options) unless pos.nil? @best ||= idx best ||= pos if pos > best best = pos @best = idx end end end return best # parse uses this to know which item was found end # call this for unrecognized options return old_string_rindex_method_4gstring(search,from) unless search.class == BitSet if options.include? :ignore return self.downcase.rindex(search.add_opposing_case,from) end idx = (from < 0) ? length + from : from return nil if idx < 0 until (search.include? (self[idx])) do idx -= 1 return nil if idx < 0 end return idx end
# File lib/gstring.rb, line 507 def rot_crypt(pswd="Standard Password should never be used!") raise "illegal password" if pswd.empty? rtn = "" ptr = 0 rnd = Random.new(pswd.rehash) len = pswd.length self.each_char do |ch| ss = @@rot_hash[ch] if ss.nil? # make no subs rtn += ch else # pos = (ch.ord + pswd[ptr].ord + rnd.rand(ROT_LEN)) % ROT_LEN pos = (ss + pswd[ptr].ord + rnd.rand(ROT_LEN)) % ROT_LEN rtn += ROT_STRING[pos] end ptr += 1 ptr = 0 if ptr >= len end return rtn end
# File lib/gstring.rb, line 528 def rot_decrypt(pswd="Standard Password should never be used!") raise "illegal password" if pswd.empty? rtn = "" ptr = 0 rnd = Random.new(pswd.rehash) len = pswd.length self.each_char do |ch| ss = @@rot_hash[ch] if ss.nil? # make no subs rtn += ch else pos = @@rot_hash[ch] # got back the number pos = pos - pswd[ptr].ord - rnd.rand(ROT_LEN) pos = pos % ROT_LEN # rtn += pos.chr(Encoding::UTF_8) rtn += ROT_STRING[pos] end ptr += 1 ptr = 0 if ptr >= len end return rtn end
# File lib/gstring.rb, line 1193 def shuffle return self.split('').shuffle.join end
# File lib/gstring.rb, line 1197 def shuffle! replace shuffle end
# File lib/gstring.rb, line 430 def sort self.split('').sort.join('') end
# File lib/gstring.rb, line 434 def sort! replace self.split('').sort.join('') end
# File lib/gstring.rb, line 1141 def split_on_set(set=' ') str = dup if (set.nil? || set.empty?) set = ' ' end set = set.to_bset prefx = str.extract_leading_set!(set) pstfx = str.extract_trailing_set!(set) dat = [] tok = [] loop do break if str.empty? dat.push str.parse(set, :no_strip) tmp = str.parsed break if tmp.nil? tmp += str.extract_leading_set!(set) tok.push tmp end dat.push str unless str.empty? return [dat,tok,prefx,pstfx] end
# File lib/gstring.rb, line 1201 def sublist(*prms) if (prms.first.class==Symbol) if prms.first == :bang prms = prms[1] else raise "illegal sublist parameter" end end prms.reverse! cls = prms.pop flags = {} dflt = nil subh = nil # substitution hash suba = nil # substitution array cnt = nil until prms.empty? tmp = prms.pop if(tmp.class==Array) raise "parameter error" unless suba.nil? suba = tmp.reverse # make it easy to pop, and makes a new instance elsif (tmp.class==Hash) raise "parameter error" unless subh.nil? subh = {} tmp.each do |key,val| subh[key.to_s] = val.to_s # convert keys and values to strings end elsif (tmp.class==Symbol) flags[tmp] = true elsif (tmp.class==Fixnum) raise "count parameter repeated" unless cnt.nil? cnt = tmp elsif (tmp.class==String) raise "parameter error" unless dflt.nil? dflt = tmp else raise "unknown parameter type" end end str = self.dup ptr = 0 rtn = "" cls = [cls] if (String==cls.class) fa = [] # add more as needed later ... fa.push :ignore if flags.include? :ignore fass = fa + [:no_strip] + [:no_skip] cls = [cls] if (BitSet==cls.class) # push everything into an array even regx cls = [cls] if (Regexp==cls.class) flst = (flags.include? :first) ? {} : nil # remove nil values subh ||= {} suba ||= [] dflt ||= "" if flags.include? :ignore # update substitution hash keys to lower case if :ignore unless subh.empty? tmp = {} subh.each do |key,val| tmp[key.downcase] = val.to_s end subh = tmp end end unless (Hash==cls.class) loop do unless cnt.nil? if (cnt <= 0) rtn += str return rtn end end rtn += str.parse(cls, fass) # make sure we are working on arrays of a bunch of stuff including nested === add test case break if str.parsed.nil? unless flst.nil? # process first flag exceptions key = (flags.include? :ignore) ? str.parsed.downcase : str.parsed if flst.include? key rtn += str.parsed # make no substitution cnt -= 1 unless cnt.nil? next else flst[key] = true # mark as taboo on future substitutions end end # first check to see if we have a hash match unless subh.empty? key = (flags.include? :ignore) ? str.parsed.downcase : str.parsed dat = subh[key] unless dat.nil? rtn += dat return rtn if str.empty? cnt -= 1 unless cnt.nil? next end end # next check to see if we have substitution data in the array unless suba.empty? rtn += suba.pop return rtn if str.empty? cnt -= 1 unless cnt.nil? next end # at last use the default if flags.include? :stop # do not make substitutions with default rtn += str.parsed rtn += str return rtn elsif flags.include? :skip # skip over, then keep going rtn += str.parsed else rtn += dflt end return rtn if str.empty? cnt -= 1 unless cnt.nil? end # loop return rtn else # (Hash==cls.class) cls = cls.dup loop do unless cnt.nil? if (cnt <= 0) rtn += str return rtn end end pos = nil best = nil bval = nil cls.each do |key,val| idx = str.index(key.to_s, 0 , fa) unless idx.nil? pos ||= idx best ||= key.to_s bval ||= val.to_s if(idx < pos) pos = idx best = key.to_s bval = val.to_s end break if idx.zero? # can't get better than zero, so stop looking end end if best.nil? rtn += str return rtn end # byebug if flags.include? :ignore rtn += str.parse(best, fass) break if str.parsed.nil? if flags.include? :first cls.delete best cls.delete best.to_sym # just in case end rtn += bval cnt -= 1 unless cnt.nil? end #loop return rtn end end
# File lib/gstring.rb, line 1367 def sublist!(*prms) replace sublist(:bang, prms) end
# File lib/gstring.rb, line 238 def swapchar(pos, ch, *modes) modes = modes.first if modes.first.class==Array rtn = self[pos] return nil if rtn.nil? if ch.empty? return nil unless modes.include? :empty_ok end unless ch.empty? ch = ch.first unless modes.include? :substring end if modes.include? :casehold if rtn.upcase? self[pos]=ch.upcase elsif rtn.downcase? self[pos]=ch.downcase else self[pos]=ch.first end else self[pos]=ch # standard mode end rtn end
# File lib/gstring.rb, line 1387 def to_crlf rtn = "" state = :normal each_char do |ch| if :normal == state if "\r" == ch state = :r_pending elsif "\n" == ch rtn += "\r\n" else rtn += ch end else if "\n" == ch rtn += "\r\n" else rtn += "\r" rtn += ch end state = :normal end end return rtn end
# File lib/gstring.rb, line 1437 def to_crlf! self.replace to_crlf self end
# File lib/gstring.rb, line 1587 def to_eng(pa=6, unit=nil) return self.to_f.to_eng(pa, unit) end
# File lib/gstring.rb, line 1412 def to_lf # convert \r\n to \n rtn = "" state = :normal each_char do |ch| if :normal == state if "\r" == ch state = :r_pending elsif "\n" == ch rtn += "\012" else rtn += ch end else if "\n" == ch rtn += "\n" else rtn += "\r" rtn += ch end state = :normal end end return rtn end
# File lib/gstring.rb, line 1442 def to_lf! # removes \r self.replace to_lf self end
# File lib/gstring.rb, line 1371 def to_num # convert to integer or float depending on format self.dup.extract_num! end
# File lib/gstring.rb, line 1591 def to_scd(dp=nil, delim = ',.') num = to_num if(dp.nil?) if num.class==Float return num.to_scd(2,delim) else return num.to_scd(0,delim) end end return num.to_scd(dp,delim) end
# File lib/gstring.rb, line 162 def to_subscript(html=false) return '<sub>' + self + '</sub>' if html rtn = "" each_char do |ch| rtn += String::SET_SUB_CHARS.include?(ch) ? @@gs_sub_hash[ch] : ch end return rtn end
# File lib/gstring.rb, line 153 def to_superscript(html=false) return '<sup>' + self + '</sup>' if html rtn = "" each_char do |ch| rtn += String::SET_SUP_CHARS.include?(ch) ? @@gs_sup_hash[ch] : ch end return rtn end
# File lib/gstring.rb, line 1752 def uchr first end
# File lib/gstring.rb, line 744 def unenclose(escape=nil) # unescape return nil if length < 2 unless first==last return nil unless last == @@gs_bracketing_pairs[first] end if @@gs_bracketing_pairs.include? first return nil if first==last end str = self[1..(length-2)] unless escape.nil? str = str.gsub(escape) { '' } # blind removal? ... may need to rethink this a tad end return str end
# File lib/gstring.rb, line 759 def unenclose!(escape=nil) str = unenclose(escape) replace str unless str.nil? str.nil? ? nil : self end
# File lib/gstring.rb, line 203 def upcase? set = self.to_bset return false if String::SET_LOWERS ** set # may not have any lower return nil unless String::SET_UPPERS ** set # must have at least one upper return true end
# File lib/gstring.rb, line 1494 def wrap_to(len, *flags) # remove this as cr will mess things up # the logic below will need to be inferred as needed #if (self.length < len) # if flags.include? :array # return [self.dup] # else # return self.dup # end #end ary = [] str = self.to_lf # remove messy \r if present if flags.include? :approximate loop do tar = str.find_near(len) tmp = str.find("\n") unless tmp.nil? tar = [tmp,tmp] if tmp <= len end # now for the nasty end points and edge cases if tar.first.nil? if tar.last.nil? ary.push str.extract!(len) else ary.push str.extract!(tar.last + 1) end else if tar.last.nil? ary.push str.extract!(tar.first + 1) else # find closest fit if (len - tar.first) <= (tar.last - len) ary.push str.extract!(tar.first + 1) else ary.push str.extract!(tar.last + 1) end end end break if str.length <= len end # loop else loop do tar = str.rindex(String::SET_SPLIT_CHARS, len) tmp = str.find("\n") unless tmp.nil? tar = tmp if tmp <= len end if (tar.nil?) ary.push str.extract!(len) else ary.push str.extract!(tar+1) end break if str.length <= len end #loop end #if ary.push str ary.length.times { |ii| ary[ii].strip! } unless flags.include? :no_strip return ary if flags.include? :array if flags.include? :html str = ary.join '<br />' else str = ary.join "\n" end return str end
# File lib/gstring.rb, line 1115 def zap! # simple alias clear end