<commit_before>#encoding: utf-8
require "digest/md5"
require File.join(File.expand_path(File.dirname(__FILE__)),"/classifiable")
require File.join(File.expand_path(File.dirname(__FILE__)),"/cacheable")
require File.join(File.expand_path(File.dirname(__FILE__)),"/incomplete_date")

class StringDocument < String
  attr_accessor :id
end

class Text
  include Cacheable
  attr_reader :doc
  def initialize(t,offset_start=0,offset_end=-1)
    @cache_id=''
    if t.respond_to?(:id)
      @doc_id = t.id 
      @cache_id="#{@doc_id}:#{offset_start}-#{offset_end}"
      self.cache_enabled=true
    else
      t = StringDocument.new(t.to_s)
      t.id = "?"
      @doc_id = t.id 
    end

    @doc = t

    if t.respond_to?(:read)
      @text = t.read
    elsif t.respond_to?(:join)
      @text = t.join("\n")
    else
      @text = t.to_s
    end
    @cache_id += Digest::MD5.hexdigest(@text)

    @offset_start = offset_start
    @offset_end = offset_end

  end
  LETRAS='áéíóúñüça-z'
  LETRASM='ÁÉÍÓÚÑÜA-Z'
  # Palabra Palabra|de|del
  NOMBRES_PROPIOS_RE="(?:[#{LETRASM}][#{LETRAS}#{LETRASM}]{2,}(?:[ ,](?:[#{LETRASM}][#{LETRASM}#{LETRAS}]+|(?:(?:de|la|del)(?= [#{LETRASM}])))){1,})"    
  NOMBRE_PROPIO_RE="(?:[#{LETRASM}][#{LETRAS}]+(?:[ ,](?:[#{LETRASM}][#{LETRASM}#{LETRAS}]+|(?:(?:de|la|del)(?= ))))*)"    
  DIRECCIONES_RE=Regexp.new("(?<!^)((?:Av.? )?#{NOMBRE_PROPIO_RE}+ [0-9]{1,5}(?![0-9\/])(,? )?#{NOMBRE_PROPIO_RE}*)")
  MESES = %w{enero febrero marzo abril mayo junio julio agosto septiembre octubre noviembre diciembre}
  MESES_RE="(?:#{MESES.join("|")})"
  FECHAS_RE=Regexp.new("(?<![0-9])(?<day>[0-9]{1,2})? *[º°]? *(?:del?)? *\\b(?<month>#{MESES_RE})\\b *(?:del?)? *´?(?<year>(20([01][0-9])|19[0-9]{2}|[0-9]{2})?(?![0-9]))|(?<day>[123]?[0-9])[-/](?<month>[01]?[0-9])([-/](?<year>20([01][0-9])|19[0-9]{2}|[0-9]{2}))?",Regexp::IGNORECASE)

  def dates
    res=cache_fetch("dates_#{@cache_id}"){
      find(FECHAS_RE)
    }
    res.map{|date| 
      d = date.match(FECHAS_RE)
      day=d["day"].to_i
      if MESES.index(d["month"])
        month=MESES.index(d["month"]) + 1
      else
        month = d["month"].to_i
      end
      year=d["year"].to_i
      if year > 0 and year < 100
        year += 1900
      end
      day = nil if day == 0
      begin
        DateWithContext.new_with_context([year,month,day],date.text,date.start_pos,date.end_pos,date.doc)
      rescue ArgumentError
        nil
      end
    }.compact
  end

  def addresses(other=nil)
    # Nombres propios, seguidos de un numero
    cache_fetch("addrs_#{@other.to_s}_#{@cache_id}"){
      a = find(DIRECCIONES_RE).map{|d| Text::Address.new_from_string_with_context(d)}

      if other and other.length > 0
        re=Regexp.new(other.compact.map(&:strip).find_all{|p| p.length > 0}.join("|"))
        a += find(re).map{|d| Text::Address.new_from_string_with_context(d)}
      end
    }
  end
  def person_names
    cache_fetch("person_names_#{@cache_id}"){
      find(Regexp.new("(#{NOMBRES_PROPIOS_RE})"),PersonName)
    }
  end
  def to_s
    @text[@offset_start ... @offset_end]
  end

  def debug()
    STDERR.write("#{Time.now} - #{yield}\n") if ENV['DEBUG'] 
  end
  def find(re,t=Result)
    if @offset_start > 0 || @offset_end > -1
      debug{"Find in fragment: #{@offset_start} ... #{@offset_end}"}
      @searchable_fragment ||= @text[@offset_start ... @offset_end]
    else<commit_msg>bugfix w/ Text#addresses<commit_after>#encoding: utf-8
require "digest/md5"
require File.join(File.expand_path(File.dirname(__FILE__)),"/classifiable")
require File.join(File.expand_path(File.dirname(__FILE__)),"/cacheable")
require File.join(File.expand_path(File.dirname(__FILE__)),"/incomplete_date")

class StringDocument < String
  attr_accessor :id
end

class Text
  include Cacheable
  attr_reader :doc
  def initialize(t,offset_start=0,offset_end=-1)
    @cache_id=''
    if t.respond_to?(:id)
      @doc_id = t.id 
      @cache_id="#{@doc_id}:#{offset_start}-#{offset_end}"
      self.cache_enabled=true
    else
      t = StringDocument.new(t.to_s)
      t.id = "?"
      @doc_id = t.id 
    end

    @doc = t

    if t.respond_to?(:read)
      @text = t.read
    elsif t.respond_to?(:join)
      @text = t.join("\n")
    else
      @text = t.to_s
    end
    @cache_id += Digest::MD5.hexdigest(@text)

    @offset_start = offset_start
    @offset_end = offset_end

  end
  LETRAS='áéíóúñüça-z'
  LETRASM='ÁÉÍÓÚÑÜA-Z'
  # Palabra Palabra|de|del
  NOMBRES_PROPIOS_RE="(?:[#{LETRASM}][#{LETRAS}#{LETRASM}]{2,}(?:[ ,](?:[#{LETRASM}][#{LETRASM}#{LETRAS}]+|(?:(?:de|la|del)(?= [#{LETRASM}])))){1,})"    
  NOMBRE_PROPIO_RE="(?:[#{LETRASM}][#{LETRAS}]+(?:[ ,](?:[#{LETRASM}][#{LETRASM}#{LETRAS}]+|(?:(?:de|la|del)(?= ))))*)"    
  DIRECCIONES_RE=Regexp.new("(?<!^)((?:Av.? )?#{NOMBRE_PROPIO_RE}+ [0-9]{1,5}(?![0-9\/])(,? )?#{NOMBRE_PROPIO_RE}*)")
  MESES = %w{enero febrero marzo abril mayo junio julio agosto septiembre octubre noviembre diciembre}
  MESES_RE="(?:#{MESES.join("|")})"
  FECHAS_RE=Regexp.new("(?<![0-9])(?<day>[0-9]{1,2})? *[º°]? *(?:del?)? *\\b(?<month>#{MESES_RE})\\b *(?:del?)? *´?(?<year>(20([01][0-9])|19[0-9]{2}|[0-9]{2})?(?![0-9]))|(?<day>[123]?[0-9])[-/](?<month>[01]?[0-9])([-/](?<year>20([01][0-9])|19[0-9]{2}|[0-9]{2}))?",Regexp::IGNORECASE)

  def dates
    res=cache_fetch("dates_#{@cache_id}"){
      find(FECHAS_RE)
    }
    res.map{|date| 
      d = date.match(FECHAS_RE)
      day=d["day"].to_i
      if MESES.index(d["month"])
        month=MESES.index(d["month"]) + 1
      else
        month = d["month"].to_i
      end
      year=d["year"].to_i
      if year > 0 and year < 100
        year += 1900
      end
      day = nil if day == 0
      begin
        DateWithContext.new_with_context([year,month,day],date.text,date.start_pos,date.end_pos,date.doc)
      rescue ArgumentError
        nil
      end
    }.compact
  end

  def addresses(other=nil)
    # Nombres propios, seguidos de un numero
    cache_fetch("addrs_#{@other.to_s}_#{@cache_id}"){
      a = find(DIRECCIONES_RE).map{|d| Text::Address.new_from_string_with_context(d)}

      if other and other.length > 0
        re=Regexp.new(other.compact.map(&:strip).find_all{|p| p.length > 0}.join("|"))
        a += find(re).map{|d| Text::Address.new_from_string_with_context(d)}
      end
      a
    }
  end
  def person_names
    cache_fetch("person_names_#{@cache_id}"){
      find(Regexp.new("(#{NOMBRES_PROPIOS_RE})"),PersonName)
    }
  end
  def to_s
    @text[@offset_start ... @offset_end]
  end

  def debug()
    STDERR.write("#{Time.now} - #{yield}\n") if ENV['DEBUG'] 
  end
  def find(re,t=Result)
    if @offset_start > 0 || @offset_end > -1
      debug{"Find in fragment: #{@offset_start} ... #{@offset_end}"}
      @searchable_fragment ||= @text[@offset_start ... @offset_end]
    else
{'fraction_non_alphanumeric': 0.22035645897775813, 'fraction_numerical': 0.021210782147591693, 'mean_word_length': 3.660260809883322, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1241737', 'n_tokens_mistral': 2917, 'n_tokens_neox': 2864, 'n_words': 380}