#encoding: utf-8 require "php4r" #This module contains various methods to escape, change or treat strings. module Knj::Strings #Returns a string that is safe to use on the command line. def self.UnixSafe(tha_string) return tha_string.to_s.gsub(" ", "\\ ").gsub("&", "\&").gsub("(", "\\(").gsub(")", "\\)").gsub('"', '\"').gsub("\n", "\"\n\"").gsub(":", "\\:").gsub('\'', "\\\\'").gsub("`", "\\\\`") end #Alias for UnixSafe. def self.unixsafe(string) return Knj::Strings.UnixSafe(string) end #Returns true if given string is regex-compatible. def self.is_regex?(str) if str.to_s.match(/^\/(.+)\/(i|m|x|)$/) return true else return false end end #Returns a Regexp-object from the string formatted as what you would give to Php's preg_match. def self.regex(str) first_char = str[0, 1] raise "First char should be '/' but wasnt: '#{first_char}'." if first_char != "/" first_pos = 1 second_pos = str.rindex("/") pattern = str[first_pos, second_pos - 1] flags = str[second_pos + 1, str.length].to_s arg_two = 0 if flags flags.length.times do |i| arg = flags[i, 1] case arg when "i" arg_two |= Regexp::IGNORECASE when "m" arg_two |= Regexp::MULTILINE when "x" arg_two |= Regexp::EXTENDED when "U" raise ArgumentError, "Ruby does (as far as I know) not support the 'U'-modifier. You should rewrite your regex with non-greedy operators such as '(\d+?)' instead for: '#{str}'." else raise "Unknown argument: '#{arg}'." end end end return Regexp.new(pattern, arg_two) end #Partens a string up in blocks for whatever words can be used to search for. Supports a block or returns an array. def self.searchstring(string, &block) words = [] if !block string = string.to_s matches = string.scan /(\"(.+?)\")/ matches.each do |matcharr| word = matcharr[1] if word and word.length > 0 if block yield(matcharr[1]) else words << matcharr[1] end string = string.gsub(matcharr[0], "") end end string.split(/\s/).each do |word| if word and word.length > 0 if block yield(word) else words << word end end end return nil if block return words end #Returns boolean if the strings is a correctly formatted email: k@spernj.org. def self.is_email?(str) return true if str.to_s.match(/^\S+@\S+\.\S+$/) return false end #Returns boolean if the string is a correctly formatted phonenumber as: +4512345678. def self.is_phonenumber?(str) return true if str.to_s.match(/^\+\d{2}\d+$/) return false end def self.js_safe(str, args = {}) str = "#{str}" if args[:quotes_to_single] str.gsub!('"', "'") end str = str.gsub("\r", "").gsub("\n", "\\n").gsub("'", "\\\\'") if !args.key?(:quotes) or args[:quotes] str.gsub!('"', '\"') end return str end #Returns 'Yes' or 'No' based on a value. The value can be 0, 1, yes, no, true or false. def self.yn_str(value, str_yes = "Yes", str_no = "No") value = value.to_i if (Float(value) rescue false) value_s = value.to_s if value.is_a?(Integer) if value == 0 return str_no else return str_yes end end return str_no if !value or value_s == "no" or value_s == "false" or value_s == "" return str_yes end #Shortens a string to maxlength and adds "..." if it was shortened. #===Examples # Knj::Strings.shorten("Kasper Johansen", 6) #=> "Kasper..." def self.shorten(str, maxlength) str = str.to_s str = str.slice(0..(maxlength - 1)).strip + "..." if str.length > maxlength return str end #Search for what looks like links in a string and does something with it based on block given or arguments given. #===Examples # str = "asd asd asd asdjklqwejqwer http://www.google.com asdfas df asf" # Knj::Strings.html_links(str) #=> "asd asd asd asdjklqwejqwer http://www.google.com asdfas df asf" # Knj::Strings.html_links(str){ |data| str.gsub(data[:match][0], "!!!#{data[:match][1]}!!!")} #=> "asd asd asd asdjklqwejqwer !!!www!!! asdfas df asf" def self.html_links(str, args = {}) Knj::Web.html(str).scan(/(http:\/\/([A-z]+)\S*\.([A-z]{2,4})(\S+))/) do |match| if block_given? str = yield(:str => str, :args => args, :match => match) else if args["target"] html = "#{match[0]}" str = str.gsub(match[0], html) end end return str end #Strips various given characters from a given string. #===Examples # Knj::Strings.strip("...kasper...", {:right => false, :left => true, :strips => [".", ","]}) #=> "kasper..." def self.strip(origstr, args) newstr = "#{origstr}" if !args.key?(:right) or args[:right] loop do changed = false args[:strips].each do |str| len = str.length endstr = newstr.slice(-len, len) next if !endstr if endstr == str changed = true newstr = newstr.slice(0..newstr.length-len-1) end end break if !changed end end if !args.key?(:left) or args[:left] loop do changed = false args[:strips].each do |str| len = str.length endstr = newstr.slice(0, len) next if !endstr if endstr == str changed = true newstr = newstr.slice(len..-1) end end break if !changed end end return newstr end #Returns the module from the given string - even if formed as SomeClass::SomeNewClass. def self.const_get_full(str) raise "Invalid object: '#{str.class.name}'." if !str.is_a?(String) and !str.is_a?(Symbol) module_use = Kernel str.to_s.scan(/(.+?)(::|$)/) do |match| module_use = module_use.const_get(match[0]) end return module_use end #Email content may only be 1000 characters long. This method shortens them gracefully. def self.email_str_safe(str) str = str.to_s strcopy = "#{str}" str.each_line("\n") do |substr_orig| substr = "#{substr_orig}" next if substr.length <= 1000 lines = [] while substr.length > 1000 do whitespace_index = substr.rindex(/\s/, 1000) if whitespace_index == nil lines << substr.slice(0, 1000) substr = substr.slice(1000, substr.length) else lines << substr.slice(0, whitespace_index + 1) substr = substr.slice(whitespace_index + 1, substr.length) end end lines << substr strcopy.gsub!(/^#{Regexp.escape(substr_orig)}$/, lines.join("\n")) end return strcopy end #Returns a float as human locaically readable. 1.0 will be 1, 1.5 will be 1.5 and so on. def self.float_as_human_logic(floatval) raise "Not a float." if !floatval.is_a?(Float) float_s = floatval.to_s parts = float_s.split(".") if parts[1].to_i > 0 return float_s else return parts[0].to_s end end #Returns a short time-format for the given amount of seconds. def self.secs_to_human_short_time(secs, args = nil) secs = secs.to_i return "#{secs}s" if secs < 60 and (!args or !args.key?(:secs) or args[:secs]) mins = (secs.to_f / 60.0).floor if mins < 60 and (!args or !args.key?(:mins) or args[:mins]) return "#{mins.to_i}m" end hours = (mins.to_f / 60.0) return "#{Knj::Locales.number_out(hours, 1)}t" end #Returns a human readable time-string from a given number of seconds. def self.secs_to_human_time_str(secs, args = nil) secs = secs.to_i hours = (secs.to_f / 3600.0).floor.to_i secs = secs - (hours * 3600) mins = (secs.to_f / 60).floor.to_i secs = secs - (mins * 60) str = "#{"%02d" % hours}:#{"%02d" % mins}" if !args or !args.key?(:secs) or args[:secs] str << ":#{"%02d" % secs}" end return str end #Turns a human readable time-string into a number of seconds. def self.human_time_str_to_secs(str) match = str.match(/^\s*(\d+)\s*:\s*(\d+)(\s*:\s*(\d+)\s*|)/) raise "Could not match string: '#{str}'." if !match hours = match[1].to_i minutes = match[2].to_i secs = match[4].to_i total = (hours * 3600) + (minutes * 60) + secs return total end #Same as 'Class#is_a?' but takes a string instead of the actual class. Then it doesnt get autoloaded or anything like that. It can also test against an array containing string-class-names. def self.is_a?(obj, str) obj_class = obj.class str = str.to_s if !str.is_a?(Array) loop do if str.is_a?(Array) return true if str.index(obj_class.name.to_s) != nil else return true if obj_class.name.to_s == str end obj_class = obj_class.superclass break if !obj_class end return false end end