Мартин обнови решението на 25.11.2012 11:42 (преди почти 12 години)
+class PrivacyFilter
+ attr_accessor :preserve_phone_country_code, :preserve_email_hostname, :partially_preserve_email_username
+
+ def initialize(text)
+ @text = text.split(/\s+/)
+ @preserve_phone_country_code = false
+ @preserve_email_hostname = false
+ @partially_preserve_email_username = false
+ end
+
+ def filtered
+ concat = lambda {|word,other| word + ' ' + other}
+ filter.inject &concat
+ end
+
+ def filter
+ @text.map do |word|
+ if Validations.email?(word) then email_filter(word)
+ elsif Validations.phone?(word) then phone_filter(word)
+ else word
+ end
+ end
+ end
+
+ def phone_filter(phone)
+ return "[PHONE]" unless preserve_phone_country_code
+ if /\A((00|\+)[1-9]\d{0,2})([\s()-]{,2}\d){6,11}\z/ =~ phone then "#{$1} [FILTERED]"
+ else "[PHONE]"
+ end
+ end
+
+ def email_filter(email)
+ return "[EMAIL]" unless preserve_email_hostname or partially_preserve_email_username
+ if partially_preserve_email_username then partial_email_filter(email)
+ else email.sub(/\A.+(?=@)/,"[FILTERED]")
+ end
+ end
+
+ def partial_email_filter(word)
+ if word.match(/\A.{,5}(?=@)/) then word.sub(/\A.+(?=@)/,"[FILTERED]")
+ else word.sub(/(?<=...).+(?=@)/,"[FILTERED]")
+ end
+ end
+end
+
+module Validations
+ def self.email?(value)
+ return false unless email = /\A[[:alnum:]][\w\+\.-]{,200}@(?<hostname>.+)\z/.match(value)
+ self.hostname?(email[:hostname])
+ end
+
+ def self.phone?(value)
+ local_format = /\A0([\s()-]{,2}\d){6,11}\z/
+ inter_format = /\A(00|\+)[1-9]\d{0,2}([\s()-]{,2}\d){6,11}\z/
+ return false unless value =~ local_format or value =~ inter_format
+ true
+ end
+
+ def self.hostname?(value)
+ hostname = /\A(?<domains>.+\.)[[:alpha:]]{2,3}(.[[:alpha:]]{2})?\z/.match(value)
+ return false unless hostname
+ return false unless hostname[:domains] =~ /\A(([A-Za-z\d]\.)|([A-Za-z\d][-\dA-Za-z]{,60}[A-Za-z\d])\.)+\z/
+ true
+ end
+
+ def self.ip_address?(value)
+ return false unless value =~ /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\z/
+ if $1.to_i > 255 or $2.to_i > 255 or $3.to_i > 255 or $4.to_i > 255 then false
+ else true
+ end
+ end
+
+ def self.integer?(value)
+ value =~ /\A0\z|\A-?[1-9]\d*\z/
+ end
+
+ def self.number?(value)
+ value =~ /\A0\z|\A-?[1-9]\d*\z|\A-?[1-9]\d*\.\d+\z|\A-?0.\d+\z/
+ end
+
+ def self.date?(value)
+ return false unless value =~ /\A(\d{4})-(\d{2})-(\d{2})\z/
+ if $3.to_i > 31 or $2.to_i > 12 or $2.to_i < 1 or $3.to_i < 1 then false
+ else true
+ end
+ end
+
+ def self.time?(value)
+ return false unless value =~ /\A(\d{1,2}):(\d{2}):(\d{2})\z/
+ if $1.to_i > 23 or $2.to_i > 59 or $3.to_i > 59 then false
+ else true
+ end
+ end
+
+ def self.date_time?(value)
+ return false unless value =~ /\A(\S*)[T ](\S*)\z/
+ self.date? $1 and self.time? $2
+ end
+end