Class: Kotoshu::Readers::PhonetTable

Inherits:
Object
  • Object
show all
Defined in:
lib/kotoshu/readers/aff_data.rb

Overview

Phonetic table for PHONE directive.

Domain object wrapping the parsed PHONE rules. Rules are indexed by their first letter so the metaphone algorithm can look up candidates in O(1) per character position.

Defined Under Namespace

Classes: Rule

Constant Summary collapse

RULE_PATTERN =

Pattern for matching phonetic rules. Updated to support extended ASCII (Latin-1) characters like É, À, etc.

/^(?<letters>[[:alpha:]]+)(\((?<optional>[[:alpha:]]+)\))?(?<lookahead>-+)?(?<flags>[\^$<]*)(?<priority>\d)?$/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(table) ⇒ PhonetTable

Create a new phonetic table.

Parameters:

  • table (Array<Array<String>>)

    Array of [pattern, replacement] pairs



403
404
405
406
407
408
409
410
# File 'lib/kotoshu/readers/aff_data.rb', line 403

def initialize(table)
  @table = table
  @rules = Hash.new { |h, k| h[k] = [] }

  table.each do |search, replacement|
    @rules[search[0]] << parse_rule(search, replacement)
  end
end

Instance Attribute Details

#rulesHash<String, Array<Rule>>

First-char → rule list

Returns:

  • (Hash<String, Array<Rule>>)

    the current value of rules



351
352
353
# File 'lib/kotoshu/readers/aff_data.rb', line 351

def rules
  @rules
end

#tableObject (readonly)

Returns the value of attribute table.



352
353
354
# File 'lib/kotoshu/readers/aff_data.rb', line 352

def table
  @table
end

Instance Method Details

#empty?Boolean

Whether this table contains any rules.

Returns:

  • (Boolean)


415
416
417
# File 'lib/kotoshu/readers/aff_data.rb', line 415

def empty?
  @table.empty?
end

#parse_rule(search, replacement) ⇒ Rule

Parse a phonetic rule.

Parameters:

  • search (String)

    Search pattern

  • replacement (String)

    Replacement string ("_" means silent/empty, per aspell's phonetic convention which Hunspell inherited)

Returns:

  • (Rule)

    Parsed rule

Raises:

  • (ArgumentError)


425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/kotoshu/readers/aff_data.rb', line 425

def parse_rule(search, replacement)
  match = RULE_PATTERN.match(search)
  raise ArgumentError, "Not a proper rule: #{search.inspect}" unless match

  text = match['letters'].chars
  text << "[#{match['optional']}]" if match['optional']

  if match['lookahead']
    lookahead_len = match['lookahead'].length
    regex = text[0...-lookahead_len].join + "(?=#{text[-lookahead_len..].join})"
  else
    regex = text.join
  end

  # Aspell/Hunspell phonetic convention: "_" in the replacement column
  # means "produce nothing" (silent). Normalizing here means downstream
  # code can append the replacement verbatim.
  normalized_replacement = replacement == '_' ? '' : replacement

  Rule.new(
    search: Regexp.new(regex),
    replacement: normalized_replacement,
    start: match['flags']&.include?('^'),
    end: match['flags']&.include?('$'),
    priority: match['priority']&.to_i || 5,
    followup: !match['lookahead'].nil?
  )
end