Module: NEU::MODS::TextNormalizer
- Defined in:
- lib/neu/mods/text_normalizer.rb
Overview
Cleans curator text for the JSON access copy and Solr, byte for byte as Atlas's TextNormalizer does; the XML preservation copy is never touched. See docs/text-normalization.md for the pipeline.
Keep this file pure ASCII: build every character class from codepoints through char_class, never from a literal character.
Constant Summary collapse
- DASH_CODEPOINTS =
U+2053 (swung dash) is not listed: it maps to "~", as in v1.
[ 0x002D, 0x058A, 0x05BE, 0x1400, 0x1806, 0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2043, 0x207B, 0x208B, 0x2212, 0x2E17, 0x2E1A, 0x2E3A, 0x2E3B, 0x2E40, 0x301C, 0x3030, 0x30A0, 0xFE31, 0xFE32, 0xFE58, 0xFE63, 0xFF0D ].freeze
- DASH_RE =
char_class(DASH_CODEPOINTS).freeze
- SWUNG_DASH_RE =
char_class([0x2053]).freeze
- SOFT_HYPHEN_RE =
Dropped, not made a hyphen: a hyphen would split one word into two Solr tokens.
char_class([0x00AD]).freeze
- SEPARATOR_CONTROL_CODEPOINTS =
Word's manual line break and page break. They become a newline, because deleting one runs the words on either side together.
[0x000B, 0x000C].freeze
- SEPARATOR_CONTROL_RE =
char_class(SEPARATOR_CONTROL_CODEPOINTS).freeze
- CONTROL_CODEPOINTS =
The rest of C0 and C1, keeping tab and newline. Dropping U+000D reduces CRLF to one newline.
((0x0000..0x0008).to_a + (0x000D..0x001F).to_a + (0x007F..0x009F).to_a).freeze
- CONTROL_RE =
char_class(CONTROL_CODEPOINTS).freeze
- HORIZONTAL_WS_CODEPOINTS =
[ 0x0009, 0x00A0, 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000 ].freeze
- HORIZONTAL_WS_RE =
Leading literal space included in the class (the " " prefix);
+so a run of horizontal whitespace collapses to a single space. Regexp.new("#{char_class(HORIZONTAL_WS_CODEPOINTS, prefix: " ").source}+").freeze
- PARAGRAPH_RUN_RE =
/\n{2,}/- GENERAL_PUNCTUATION =
U+2000..U+206F. Unlisted codepoints pass through; "" drops an invisible or format mark.
{ 0x2000 => " ", 0x2001 => " ", 0x2002 => " ", 0x2003 => " ", 0x2004 => " ", 0x2005 => " ", 0x2006 => " ", 0x2007 => " ", 0x2008 => " ", 0x2009 => " ", 0x200A => " ", 0x200B => "", 0x200C => "", 0x200D => "", 0x200E => "", 0x200F => "", 0x2018 => "'", 0x2019 => "'", 0x201A => ",", 0x201B => "'", 0x201C => '"', 0x201D => '"', 0x201E => '"', 0x201F => '"', 0x2020 => "+", 0x2021 => "+", 0x2022 => "*", 0x2023 => "*", 0x2024 => ".", 0x2025 => "..", 0x2026 => "...", 0x2028 => "\n", 0x2029 => "\n\n", 0x202A => "", 0x202B => "", 0x202C => "", 0x202D => "", 0x202E => "", 0x202F => " ", 0x2030 => "%", 0x2032 => "'", 0x2033 => '"', 0x2035 => "'", 0x2036 => '"', 0x2039 => "<", 0x203A => ">", 0x203C => "!!", 0x203D => "?", 0x2044 => "/", 0x2052 => "%", 0x205F => " ", 0x2060 => "", 0x2061 => "", 0x2062 => "", 0x2063 => "", 0x2064 => "", 0x206A => "", 0x206B => "", 0x206C => "", 0x206D => "", 0x206E => "", 0x206F => "" }.transform_keys { |cp| [cp].pack("U") }.freeze
- GENERAL_PUNCTUATION_RE =
Regexp.new("[#{format('\\u%04X-\\u%04X', 0x2000, 0x206F)}]").freeze
Class Method Summary collapse
-
.char_class(codepoints, prefix: "") ⇒ Object
Build a character-class Regexp from an array of integer codepoints, as \uXXXX escapes (keeps this source ASCII).
- .normalize(str) ⇒ Object
- .normalize_paragraphs(str) ⇒ Object
Class Method Details
.char_class(codepoints, prefix: "") ⇒ Object
Build a character-class Regexp from an array of integer codepoints, as \uXXXX escapes (keeps this source ASCII).
16 17 18 |
# File 'lib/neu/mods/text_normalizer.rb', line 16 def self.char_class(codepoints, prefix: "") Regexp.new("[#{prefix}#{codepoints.map { |cp| format('\\u%04X', cp) }.join}]") end |
.normalize(str) ⇒ Object
85 86 87 88 89 90 91 |
# File 'lib/neu/mods/text_normalizer.rb', line 85 def normalize(str) return "" if str.nil? s = base_normalize(str.to_s) s = s.tr("\n", " ") s.gsub(HORIZONTAL_WS_RE, " ").strip end |
.normalize_paragraphs(str) ⇒ Object
93 94 95 96 97 98 99 100 |
# File 'lib/neu/mods/text_normalizer.rb', line 93 def normalize_paragraphs(str) return "" if str.nil? s = base_normalize(str.to_s) s = s.gsub(HORIZONTAL_WS_RE, " ") s = s.gsub(/ *\n */, "\n") s.split(PARAGRAPH_RUN_RE).map { |p| p.tr("\n", " ").strip }.reject(&:empty?).join("\n\n") end |