module WolfCore::StringUtils
def base64_encoded?(str)
def base64_encoded?(str) return false unless str.is_a?(String) && str.length % 4 == 0 base64_regex = %r{^[A-Za-z0-9+/]+={0,2}$} str.match?(base64_regex) end
def camelcase_to_spaces(str)
def camelcase_to_spaces(str) return if str.nil? str.to_s.gsub(/([A-Z])/, ' \1').strip.downcase.capitalize end
def clean_phone_number(phone)
def clean_phone_number(phone) return if phone.nil? cleaned_phone = phone.to_s.gsub(/\D/, "") cleaned_phone[-10, 10] end
def deep_parse_json(input)
def deep_parse_json(input) while input.is_a?(String) begin input = JSON.parse(input) rescue JSON::ParserError break end end input || {} end
def hash_str_to_json(hash_str)
def hash_str_to_json(hash_str) hash_str&.to_s&.gsub("=>", ":")&.gsub('\"', '"')&.gsub("{", "{")&.gsub("}", "}")&.gsub(/(\w+)(?=\s*:)/) do |key| "\"#{key}\"" end end
def jaro_winkler_similarity(string1, string2)
def jaro_winkler_similarity(string1, string2) str1 = string1.to_s.strip.downcase str2 = string2.to_s.strip.downcase return 1.0 if str1 == str2 return 0.0 if str1.empty? || str2.empty? max_len = [str1.length, str2.length].max match_distance = [(max_len / 2) - 1, 0].max str1_matches = Array.new(str1.length, false) str2_matches = Array.new(str2.length, false) matches = 0 str1.each_char.with_index do |char, i| start = [i - match_distance, 0].max finish = [i + match_distance + 1, str2.length].min (start...finish).each do |j| next if str2_matches[j] next unless str2[j] == char str1_matches[i] = true str2_matches[j] = true matches += 1 break end end return 0.0 if matches.zero? transpositions = 0 j = 0 str1.each_char.with_index do |char, i| next unless str1_matches[i] j += 1 while j < str2.length && !str2_matches[j] break if j >= str2.length transpositions += 1 if str2[j] != char j += 1 end transpositions /= 2.0 jaro = ( (matches / str1.length.to_f) + (matches / str2.length.to_f) + ((matches - transpositions) / matches) ) / 3.0 prefix_length = 0 max_prefix = 4 while prefix_length < max_prefix && prefix_length < str1.length && prefix_length < str2.length && str1[prefix_length] == str2[prefix_length] prefix_length += 1 end jaro + (prefix_length * 0.1 * (1 - jaro)) end
def remove_blank_spaces(str)
def remove_blank_spaces(str) return if str.nil? str.to_s.gsub(/\s+/, "") end
def remove_non_alphanumeric_chars(str, exceptions: nil)
def remove_non_alphanumeric_chars(str, exceptions: nil) return if str.nil? exceptions ||= [] exceptions = Array(exceptions) escaped_exceptions = exceptions.map { |char| Regexp.escape(char) }.join regex = /[^a-zA-Z0-9#{escaped_exceptions}]/ str.to_s.gsub(regex, "") end
def split_address(address_string)
def split_address(address_string) address_string = address_string&.dup address_string ||= "" address = { street: nil, city: nil, state: nil, zip: nil } city_and_state_regex_found = false city_and_state_regex = /\b([A-Za-z\s]+),\s*([A-Za-z]{2})\b/ zip_regex = /\d{5}(?:-\d{4})?$/ street_regex = /\A([^,]+)/ state_regex = /\b[A-Za-z]{2}\b/ city_regex = /\b[a-zA-Z0-9\s]{2,}\b/ if match_data = address_string.match(city_and_state_regex) address[:city] = match_data[1].strip address[:state] = match_data[2].strip address_string.sub!(city_and_state_regex, "") city_and_state_regex_found = true end if zip_match = address_string.match(zip_regex) address[:zip] = zip_match[0].strip address_string.sub!(zip_regex, "") end if street_match = address_string.match(street_regex) address[:street] = street_match[0].strip address[:street] = nil if address[:street].empty? address_string.sub!(street_regex, "") end return address if city_and_state_regex_found if state_match = address_string.match(state_regex) address[:state] = state_match[0].strip address_string.sub!(state_regex, "") end if city_match = address_string.match(city_regex) address[:city] = city_match[0].strip address_string.sub!(city_regex, "") end address end
def split_name(full_name, name_range: nil, lastname_range: nil, if_one_word: nil)
def split_name(full_name, name_range: nil, lastname_range: nil, if_one_word: nil) if_one_word = {} unless if_one_word.is_a?(Hash) if_one_word.merge!(lastname: "-") if if_one_word[:lastname].nil? words = full_name.strip.split return { first_name: words[0], last_name: if_one_word[:lastname] } if words.length == 1 return { first_name: words[0], last_name: words[1] } if words.length == 2 name_range ||= 0..-2 lastname_range ||= -1..-1 name = words[name_range].join(" ") lastname = words[lastname_range].join(" ") { first_name: name, last_name: lastname } end
def to_kebab_case(str)
def to_kebab_case(str) return if str.nil? str.to_s.gsub(/\s+/, "-").downcase end
def to_snake_case(str)
def to_snake_case(str) return if str.nil? str.to_s.gsub(/\s+/, "_").downcase end
def valid_json?(str)
def valid_json?(str) return false unless str.is_a?(String) JSON.parse(str) true rescue JSON::ParserError false end
def valid_url?(url)
def valid_url?(url) return false unless url.instance_of?(String) uri = URI.parse(url) uri.is_a?(URI::HTTP) || (uri.is_a?(URI::HTTPS) && !uri.host.nil?) rescue URI::InvalidURIError false end