diff --git a/spec/std/char_spec.cr b/spec/std/char_spec.cr index cd521f94d5c0..5a7a4f3d751f 100644 --- a/spec/std/char_spec.cr +++ b/spec/std/char_spec.cr @@ -1,4 +1,5 @@ require "spec" +require "unicode" describe "Char" do describe "upcase" do @@ -9,6 +10,7 @@ describe "Char" do describe "downcase" do it { 'A'.downcase.should eq('a') } it { '1'.downcase.should eq('1') } + it { '\u00df'.downcase(Unicode::CaseOptions::Fold) { |equiv| equiv.should eq('s') } } end describe "succ" do diff --git a/spec/std/string_spec.cr b/spec/std/string_spec.cr index ee53d99358b5..4cf5902eecd7 100644 --- a/spec/std/string_spec.cr +++ b/spec/std/string_spec.cr @@ -469,6 +469,10 @@ describe "String" do it { "AEIİOU".downcase(Unicode::CaseOptions::Turkic).should eq("aeıiou") } it { "ÁEÍOÚ".downcase(Unicode::CaseOptions::ASCII).should eq("ÁeÍoÚ") } it { "İ".downcase.should eq("i̇") } + it { "Baffle".downcase(Unicode::CaseOptions::Fold).should eq("baffle") } + it { "ff".downcase(Unicode::CaseOptions::Fold).should eq("ff") } + it { "tschüß".downcase(Unicode::CaseOptions::Fold).should eq("tschüss") } + it { "ΣίσυφοςfiÆ".downcase(Unicode::CaseOptions::Fold).should eq("σίσυφοσfiæ") } end describe "upcase" do diff --git a/src/unicode/unicode.cr b/src/unicode/unicode.cr index 2db6b6c4325b..759fa55f2db9 100644 --- a/src/unicode/unicode.cr +++ b/src/unicode/unicode.cr @@ -22,6 +22,9 @@ module Unicode # 'ı'.upcase(Unicode::CaseOptions::Turkic) # => 'I' # ``` Turkic + + # Unicode case folding, which is more far-reaching than Unicode case mapping. + Fold end def self.upcase(char : Char, options : CaseOptions) @@ -94,6 +97,9 @@ module Unicode result = check_downcase_turkic(char, options) return result if result + results = check_downcase_fold(char, options) + return results[0].unsafe_chr if results && results.size == 1 + check_downcase_ranges(char) end @@ -110,6 +116,12 @@ module Unicode return end + result = check_downcase_fold(char, options) + if result + result.each { |c| yield c.unsafe_chr if c != 0 } + return + end + result = special_cases_downcase[char.ord]? if result result.each { |c| yield c.unsafe_chr if c != 0 } @@ -141,6 +153,13 @@ module Unicode nil end + private def self.check_downcase_fold(char, options) + if options.fold? + return fold_cases[char.ord]? + end + nil + end + private def self.check_downcase_ranges(char) result = search_ranges(downcase_ranges, char.ord) return char + result if result