module UnicodeNormalize

automatically generated by template/unicode_norm_gen.tmpl

Constants

ACCENTS
CLASS_TABLE
COMPOSITION_TABLE
DECOMPOSITION_TABLE
KOMPATIBLE_TABLE
LBASE
LCOUNT
MAX_HASH_LENGTH

Constant for max hash capacity to avoid DoS attack

NCOUNT
NF_HASH_C
NF_HASH_D
REGEXP_C
REGEXP_C_STRING
REGEXP_D

Regular Expressions and Hash Constants

REGEXP_D_STRING
REGEXP_K
REGEXP_K_STRING
SBASE
Constants For Hangul

for details such as the meaning of the identifiers below, please see www.unicode.org/versions/Unicode7.0.0/ch03.pdf, pp. 144/145

SCOUNT
TBASE
TCOUNT
UNICODE_ENCODINGS

Unicode-based encodings (except UTF-8)

VBASE
VCOUNT

Public Class Methods

canonical_ordering_one(string) click to toggle source

Canonical Ordering

# File lib/unicode_normalize/normalize.rb, line 69
def self.canonical_ordering_one(string)
  sorting = string.each_char.collect { |c| [c, CLASS_TABLE[c]] }
  (sorting.length-2).downto(0) do |i| # almost, but not exactly bubble sort
    (0..i).each do |j|
      later_class = sorting[j+1].last
      if 0<later_class and later_class<sorting[j].last
        sorting[j], sorting[j+1] = sorting[j+1], sorting[j]
      end
    end
  end
  return sorting.collect(&:first).join('')
end
hangul_comp_one(string) click to toggle source
# File lib/unicode_normalize/normalize.rb, line 53
def self.hangul_comp_one(string)
  length = string.length
  if length>1 and 0 <= (lead =string[0].ord-LBASE) and lead  < LCOUNT and
                  0 <= (vowel=string[1].ord-VBASE) and vowel < VCOUNT
    lead_vowel = SBASE + (lead * VCOUNT + vowel) * TCOUNT
    if length>2 and 0 <= (trail=string[2].ord-TBASE) and trail < TCOUNT
      (lead_vowel + trail).chr(Encoding::UTF_8) + string[3..-1]
    else
      lead_vowel.chr(Encoding::UTF_8) + string[2..-1]
    end
  else
    string
  end
end
hangul_decomp_one(target) click to toggle source

Hangul Algorithm

# File lib/unicode_normalize/normalize.rb, line 44
def self.hangul_decomp_one(target)
  syllable_index = target.ord - SBASE
  return target if syllable_index < 0 || syllable_index >= SCOUNT
  l = LBASE + syllable_index / NCOUNT
  v = VBASE + (syllable_index % NCOUNT) / TCOUNT
  t = TBASE + syllable_index % TCOUNT
  (t==TBASE ? [l, v] : [l, v, t]).pack('U*') + target[1..-1]
end
nfc_one(string) click to toggle source
# File lib/unicode_normalize/normalize.rb, line 88
def self.nfc_one(string)
  nfd_string = nfd_one string
  start = nfd_string[0]
  last_class = CLASS_TABLE[start]-1
  accents = ''
  nfd_string[1..-1].each_char do |accent|
    accent_class = CLASS_TABLE[accent]
    if last_class<accent_class and composite = COMPOSITION_TABLE[start+accent]
      start = composite
    else
      accents << accent
      last_class = accent_class
    end
  end
  hangul_comp_one(start+accents)
end
nfd_one(string) click to toggle source

Normalization Forms for Patterns (not whole Strings)

# File lib/unicode_normalize/normalize.rb, line 83
def self.nfd_one(string)
  string = string.chars.map! {|c| DECOMPOSITION_TABLE[c] || c}.join('')
  canonical_ordering_one(hangul_decomp_one(string))
end
normalize(string, form = :nfc) click to toggle source
# File lib/unicode_normalize/normalize.rb, line 105
def self.normalize(string, form = :nfc)
  encoding = string.encoding
  case encoding
  when Encoding::UTF_8
    case form
    when :nfc then
      string.gsub REGEXP_C, NF_HASH_C
    when :nfd then
      string.gsub REGEXP_D, NF_HASH_D
    when :nfkc then
      string.gsub(REGEXP_K, KOMPATIBLE_TABLE).gsub(REGEXP_C, NF_HASH_C)
    when :nfkd then
      string.gsub(REGEXP_K, KOMPATIBLE_TABLE).gsub(REGEXP_D, NF_HASH_D)
    else
      raise ArgumentError, "Invalid normalization form #{form}."
    end
  when Encoding::US_ASCII
    string
  when *UNICODE_ENCODINGS
    normalize(string.encode(Encoding::UTF_8), form).encode(encoding)
  else
    raise Encoding::CompatibilityError, "Unicode Normalization not appropriate for #{encoding}"
  end
end
normalized?(string, form = :nfc) click to toggle source
# File lib/unicode_normalize/normalize.rb, line 130
def self.normalized?(string, form = :nfc)
  encoding = string.encoding
  case encoding
  when Encoding::UTF_8
    case form
    when :nfc then
      string.scan REGEXP_C do |match|
        return false  if NF_HASH_C[match] != match
      end
      true
    when :nfd then
      string.scan REGEXP_D do |match|
        return false  if NF_HASH_D[match] != match
      end
      true
    when :nfkc then
      normalized?(string, :nfc) and string !~ REGEXP_K
    when :nfkd then
      normalized?(string, :nfd) and string !~ REGEXP_K
    else
      raise ArgumentError, "Invalid normalization form #{form}."
    end
  when Encoding::US_ASCII
    true
  when *UNICODE_ENCODINGS
    normalized? string.encode(Encoding::UTF_8), form
  else
    raise Encoding::CompatibilityError, "Unicode Normalization not appropriate for #{encoding}"
  end
end