diff --git a/icu4c/source/data/rbnf/be.txt b/icu4c/source/data/rbnf/be.txt index a316e0c46032..ab26dc273b16 100644 --- a/icu4c/source/data/rbnf/be.txt +++ b/icu4c/source/data/rbnf/be.txt @@ -4,8 +4,6 @@ be{ RBNFRules{ SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-numbering=;" diff --git a/icu4c/source/data/rbnf/bg.txt b/icu4c/source/data/rbnf/bg.txt index 50dc6bbe5f1c..e58a3a50e82b 100644 --- a/icu4c/source/data/rbnf/bg.txt +++ b/icu4c/source/data/rbnf/bg.txt @@ -17,8 +17,6 @@ bg{ "0: =%digits-ordinal-masculine=;" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-numbering=;" diff --git a/icu4c/source/data/rbnf/ca.txt b/icu4c/source/data/rbnf/ca.txt index 2590c4155772..6c78b52a381c 100644 --- a/icu4c/source/data/rbnf/ca.txt +++ b/icu4c/source/data/rbnf/ca.txt @@ -20,8 +20,6 @@ ca{ "0: =#,##0=es;" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-numbering=;" diff --git a/icu4c/source/data/rbnf/cy.txt b/icu4c/source/data/rbnf/cy.txt index bd85a2f288f5..50d00a132360 100644 --- a/icu4c/source/data/rbnf/cy.txt +++ b/icu4c/source/data/rbnf/cy.txt @@ -4,8 +4,6 @@ cy{ RBNFRules{ SpelloutRules{ - "%%lenient-parse:" - "& ' ' , ',' ;" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-numbering=;" diff --git a/icu4c/source/data/rbnf/da.txt b/icu4c/source/data/rbnf/da.txt index b29d16be04c3..dbf2636e4c01 100644 --- a/icu4c/source/data/rbnf/da.txt +++ b/icu4c/source/data/rbnf/da.txt @@ -4,8 +4,6 @@ da{ RBNFRules{ SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "-x: minus >>;" "x.x: =0.0=;" diff --git a/icu4c/source/data/rbnf/de.txt b/icu4c/source/data/rbnf/de.txt index 98f5c859f40b..d3895930816c 100644 --- a/icu4c/source/data/rbnf/de.txt +++ b/icu4c/source/data/rbnf/de.txt @@ -5,7 +5,7 @@ de{ RBNFRules{ SpelloutRules{ "%%lenient-parse:" - "&ue=\u00FC&ae=\u00E4&oe=\u00F6&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" + "&ue=\u00FC&ae=\u00E4&oe=\u00F6;" "%spellout-numbering-year:" "-x: minus >>;" "x.x: =0.0=;" diff --git a/icu4c/source/data/rbnf/en.txt b/icu4c/source/data/rbnf/en.txt index d0119f520d4d..02d13be178eb 100644 --- a/icu4c/source/data/rbnf/en.txt +++ b/icu4c/source/data/rbnf/en.txt @@ -25,8 +25,6 @@ en{ "3600/60: <#,##0<:>>>;" "%duration:" "0: =%in-numerals=;" - "%%lenient-parse:" - "& ':' = '.' = ' ' = '-';" } OrdinalRules{ "%digits-ordinal:" @@ -34,8 +32,6 @@ en{ "0: =#,##0=$(ordinal,one{st}two{nd}few{rd}other{th})$;" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%%2d-year:" "0: hundred;" "1: oh-=%spellout-numbering=;" diff --git a/icu4c/source/data/rbnf/es.txt b/icu4c/source/data/rbnf/es.txt index 983e884a6d1a..b9475be9df1c 100644 --- a/icu4c/source/data/rbnf/es.txt +++ b/icu4c/source/data/rbnf/es.txt @@ -23,8 +23,6 @@ es{ "0: =%digits-ordinal-masculine=;" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-numbering=;" diff --git a/icu4c/source/data/rbnf/fo.txt b/icu4c/source/data/rbnf/fo.txt index b0ee7a90f1a1..942020e46e70 100644 --- a/icu4c/source/data/rbnf/fo.txt +++ b/icu4c/source/data/rbnf/fo.txt @@ -4,8 +4,6 @@ fo{ RBNFRules{ SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "-x: m\u00EDnus >>;" "x.x: =0.0=;" diff --git a/icu4c/source/data/rbnf/fr.txt b/icu4c/source/data/rbnf/fr.txt index cc4daf645808..1d05d50ef38f 100644 --- a/icu4c/source/data/rbnf/fr.txt +++ b/icu4c/source/data/rbnf/fr.txt @@ -20,8 +20,6 @@ fr{ "0: =%digits-ordinal-masculine=;" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "-x: moins >>;" "x.x: =0.0=;" diff --git a/icu4c/source/data/rbnf/fr_BE.txt b/icu4c/source/data/rbnf/fr_BE.txt index fb9a29e6090e..69b01bff9c43 100644 --- a/icu4c/source/data/rbnf/fr_BE.txt +++ b/icu4c/source/data/rbnf/fr_BE.txt @@ -4,8 +4,6 @@ fr_BE{ RBNFRules{ SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "-x: moins >>;" "x.x: =0.0=;" diff --git a/icu4c/source/data/rbnf/fr_CH.txt b/icu4c/source/data/rbnf/fr_CH.txt index c220123ef972..913335fb9803 100644 --- a/icu4c/source/data/rbnf/fr_CH.txt +++ b/icu4c/source/data/rbnf/fr_CH.txt @@ -4,8 +4,6 @@ fr_CH{ RBNFRules{ SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "-x: moins >>;" "x.x: =0.0=;" diff --git a/icu4c/source/data/rbnf/ga.txt b/icu4c/source/data/rbnf/ga.txt index a91aaaa5d76b..6879e2b7cea5 100644 --- a/icu4c/source/data/rbnf/ga.txt +++ b/icu4c/source/data/rbnf/ga.txt @@ -42,8 +42,6 @@ ga{ "3600/60: <#,##0<:>>>;" "%duration:" "0: =%in-numerals=;" - "%%lenient-parse:" - "& ':' = '.' = ' ' = '-';" } OrdinalRules{ "%digits-ordinal:" @@ -51,8 +49,6 @@ ga{ "0: =#,##0=\u00FA;" } SpelloutRules{ - "%%lenient-parse:" - "& ' ' , ',' ;" "%spellout-numbering-year:" "-x: m\u00EDneas >>;" "x.x: =0.0=;" diff --git a/icu4c/source/data/rbnf/is.txt b/icu4c/source/data/rbnf/is.txt index 2087ac835cb0..7d847dc91996 100644 --- a/icu4c/source/data/rbnf/is.txt +++ b/icu4c/source/data/rbnf/is.txt @@ -4,8 +4,6 @@ is{ RBNFRules{ SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "-x: m\u00EDnus >>;" "x.x: =0.0=;" diff --git a/icu4c/source/data/rbnf/it.txt b/icu4c/source/data/rbnf/it.txt index 69fc6683d04e..252affa10d99 100644 --- a/icu4c/source/data/rbnf/it.txt +++ b/icu4c/source/data/rbnf/it.txt @@ -14,14 +14,13 @@ it{ "0: =%digits-ordinal-masculine=;" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-numbering=;" "%spellout-numbering:" "-x: meno >>;" "x.x: << virgola >>;" + "Inf: infinito;" "0: zero;" "1: uno;" "2: due;" @@ -88,6 +87,7 @@ it{ "%spellout-cardinal-masculine:" "-x: meno >>;" "x.x: << virgola >>;" + "Inf: infinito;" "0: zero;" "1: un;" "2: =%spellout-numbering=;" @@ -143,6 +143,7 @@ it{ "%spellout-cardinal-feminine:" "-x: meno >>;" "x.x: << virgola >>;" + "Inf: infinita;" "0: zero;" "1: una;" "2: =%spellout-numbering=;" @@ -179,16 +180,16 @@ it{ "90: novant>%%ordinal-esimo-with-a>;" "100: cent>%%ordinal-esimo-with-o>;" "200: <%spellout-cardinal-masculine<\u00ADcent>%%ordinal-esimo-with-o>;" - "1000: mille\u00AD>%%ordinal-esimo>;" - "2000: <%spellout-cardinal-masculine<[\u00ADmila\u00AD>%%ordinal-esimo>|\u00ADmillesimo];" - "1000000: milione\u00AD>%%ordinal-esimo>;" - "2000000: <%spellout-cardinal-masculine%%ordinal-esimo>;" - "1000000000: miliard\u00AD>%%ordinal-esimo-with-o>;" - "2000000000: <%spellout-cardinal-masculine%%ordinal-esimo-with-o>;" - "1000000000000: bilione\u00AD>%%ordinal-esimo>;" - "2000000000000: <%spellout-cardinal-masculine%%ordinal-esimo>;" - "1000000000000000: biliard\u00AD>%%ordinal-esimo-with-o>;" - "2000000000000000: <%spellout-cardinal-masculine%%ordinal-esimo-with-o>;" + "1000: mille>%%ordinal-esimo>;" + "2000: <%spellout-cardinal-masculine<[\u00ADmila>%%ordinal-esimo>|\u00ADmillesimo];" + "1000000: milione>%%ordinal-esimo>;" + "2000000: <%spellout-cardinal-masculine<\u00ADmilione>%%ordinal-esimo>;" + "1000000000: miliard>%%ordinal-esimo-with-o>;" + "2000000000: <%spellout-cardinal-masculine<\u00ADmiliard>%%ordinal-esimo-with-o>;" + "1000000000000: bilione>%%ordinal-esimo>;" + "2000000000000: <%spellout-cardinal-masculine<\u00ADbilion>%%ordinal-esimo>;" + "1000000000000000: biliard>%%ordinal-esimo-with-o>;" + "2000000000000000: <%spellout-cardinal-masculine<\u00ADbiliard>%%ordinal-esimo-with-o>;" "1000000000000000000: =#,##0=;" "%%ordinal-esimo:" "0: simo;" @@ -201,7 +202,7 @@ it{ "7: \u00ADsettesimo;" "8: \u00ADottesimo;" "9: \u00ADnovesimo;" - "10: =%spellout-ordinal-masculine=;" + "10: \u00AD=%spellout-ordinal-masculine=;" "%%ordinal-esimo-with-i:" "0: esimo;" "1: \u00ADunesimo;" @@ -213,7 +214,7 @@ it{ "7: i\u00ADsettesimo;" "8: \u00ADottesimo;" "9: i\u00ADnovesimo;" - "10: =%spellout-ordinal-masculine=;" + "10: \u00AD=%spellout-ordinal-masculine=;" "%%ordinal-esimo-with-a:" "0: esimo;" "1: \u00ADunesimo;" @@ -225,7 +226,7 @@ it{ "7: a\u00ADsettesimo;" "8: \u00ADottesimo;" "9: a\u00ADnovesimo;" - "10: =%spellout-ordinal-masculine=;" + "10: \u00AD=%spellout-ordinal-masculine=;" "%%ordinal-esimo-with-o:" "0: esimo;" "1: \u00ADunesimo;" @@ -271,16 +272,16 @@ it{ "90: novant>%%ordinal-esima-with-a>;" "100: cent>%%ordinal-esima-with-o>;" "200: <%spellout-cardinal-masculine<\u00ADcent>%%ordinal-esima-with-o>;" - "1000: mille\u00AD>%%ordinal-esima>;" - "2000: <%spellout-cardinal-masculine<[\u00ADmila\u00AD>%%ordinal-esima>|\u00ADmillesima]>;" - "1000000: milione\u00AD>%%ordinal-esima>;" - "2000000: <%spellout-cardinal-masculine%%ordinal-esima>;" - "1000000000: miliard\u00AD>%%ordinal-esima-with-o>;" - "2000000000: <%spellout-cardinal-masculine%%ordinal-esima-with-o>;" - "1000000000000: bilione\u00AD>%%ordinal-esima>;" - "2000000000000: <%spellout-cardinal-masculine%%ordinal-esima>;" - "1000000000000000: biliard\u00AD>%%ordinal-esima-with-o>;" - "2000000000000000: <%spellout-cardinal-masculine%%ordinal-esima-with-o>;" + "1000: mille>%%ordinal-esima>;" + "2000: <%spellout-cardinal-masculine<[\u00ADmila>%%ordinal-esima>|\u00ADmillesima];" + "1000000: milione>%%ordinal-esima>;" + "2000000: <%spellout-cardinal-masculine<\u00ADmilione>%%ordinal-esima>;" + "1000000000: miliard>%%ordinal-esima-with-o>;" + "2000000000: <%spellout-cardinal-masculine<\u00ADmiliard>%%ordinal-esima-with-o>;" + "1000000000000: bilione>%%ordinal-esima>;" + "2000000000000: <%spellout-cardinal-masculine<\u00ADbilion>%%ordinal-esima>;" + "1000000000000000: biliard>%%ordinal-esima-with-o>;" + "2000000000000000: <%spellout-cardinal-masculine<\u00ADbiliard>%%ordinal-esima-with-o>;" "1000000000000000000: =#,##0=;" "%%ordinal-esima:" "0: sima;" @@ -293,7 +294,7 @@ it{ "7: \u00ADsettesima;" "8: \u00ADottesima;" "9: \u00ADnovesima;" - "10: =%spellout-ordinal-feminine=;" + "10: \u00AD=%spellout-ordinal-feminine=;" "%%ordinal-esima-with-i:" "0: esima;" "1: \u00ADunesima;" @@ -305,7 +306,7 @@ it{ "7: i\u00ADsettesima;" "8: \u00ADottesima;" "9: i\u00ADnovesima;" - "10: =%spellout-ordinal-feminine=;" + "10: \u00AD=%spellout-ordinal-feminine=;" "%%ordinal-esima-with-a:" "0: esima;" "1: \u00ADunesima;" @@ -317,7 +318,7 @@ it{ "7: a\u00ADsettesima;" "8: \u00ADottesima;" "9: a\u00ADnovesima;" - "10: =%spellout-ordinal-feminine=;" + "10: \u00AD=%spellout-ordinal-feminine=;" "%%ordinal-esima-with-o:" "0: esima;" "1: \u00ADunesima;" @@ -363,16 +364,16 @@ it{ "90: novant>%%ordinal-esimi-with-a>;" "100: cent>%%ordinal-esimi-with-o>;" "200: <%spellout-cardinal-masculine<\u00ADcent>%%ordinal-esimi-with-o>;" - "1000: mille\u00AD>%%ordinal-esimi>;" - "2000: <%spellout-cardinal-masculine<[\u00ADmila\u00AD>%%ordinal-esimi>|\u00ADmillesimi]>;" - "1000000: milione\u00AD>%%ordinal-esimi>;" - "2000000: <%spellout-cardinal-masculine%%ordinal-esimi>;" - "1000000000: miliard\u00AD>%%ordinal-esimi-with-o>;" - "2000000000: <%spellout-cardinal-masculine%%ordinal-esimi-with-o>;" - "1000000000000: bilione\u00AD>%%ordinal-esimi>;" - "2000000000000: <%spellout-cardinal-masculine%%ordinal-esimi>;" - "1000000000000000: biliard\u00AD>%%ordinal-esimi-with-o>;" - "2000000000000000: <%spellout-cardinal-masculine%%ordinal-esimi-with-o>;" + "1000: mille>%%ordinal-esimi>;" + "2000: <%spellout-cardinal-masculine<[\u00ADmila>%%ordinal-esimi>|\u00ADmillesimi];" + "1000000: milione>%%ordinal-esimi>;" + "2000000: <%spellout-cardinal-masculine<\u00ADmilione>%%ordinal-esimi>;" + "1000000000: miliard>%%ordinal-esimi-with-o>;" + "2000000000: <%spellout-cardinal-masculine<\u00ADmiliard>%%ordinal-esimi-with-o>;" + "1000000000000: bilione>%%ordinal-esimi>;" + "2000000000000: <%spellout-cardinal-masculine<\u00ADbilion>%%ordinal-esimi>;" + "1000000000000000: biliard>%%ordinal-esimi-with-o>;" + "2000000000000000: <%spellout-cardinal-masculine<\u00ADbiliard>%%ordinal-esimi-with-o>;" "1000000000000000000: =#,##0=;" "%%ordinal-esimi:" "0: simi;" @@ -385,7 +386,7 @@ it{ "7: \u00ADsettesimi;" "8: \u00ADottesimi;" "9: \u00ADnovesimi;" - "10: =%spellout-ordinal-masculine-plural=;" + "10: \u00AD=%spellout-ordinal-masculine-plural=;" "%%ordinal-esimi-with-i:" "0: esimi;" "1: \u00ADunesimi;" @@ -397,7 +398,7 @@ it{ "7: i\u00ADsettesimi;" "8: \u00ADottesimi;" "9: i\u00ADnovesimi;" - "10: =%spellout-ordinal-masculine-plural=;" + "10: \u00AD=%spellout-ordinal-masculine-plural=;" "%%ordinal-esimi-with-a:" "0: esimi;" "1: \u00ADunesimi;" @@ -409,7 +410,7 @@ it{ "7: a\u00ADsettesimi;" "8: \u00ADottesimi;" "9: a\u00ADnovesimi;" - "10: =%spellout-ordinal-masculine-plural=;" + "10: \u00AD=%spellout-ordinal-masculine-plural=;" "%%ordinal-esimi-with-o:" "0: esimi;" "1: \u00ADunesimi;" @@ -455,16 +456,16 @@ it{ "90: novant>%%ordinal-esime-with-a>;" "100: cent>%%ordinal-esime-with-o>;" "200: <%spellout-cardinal-masculine<\u00ADcent>%%ordinal-esime-with-o>;" - "1000: mille\u00AD>%%ordinal-esime>;" - "2000: <%spellout-cardinal-masculine<[\u00ADmila\u00AD>%%ordinal-esime>|\u00ADmillesime]>;" - "1000000: milione\u00AD>%%ordinal-esime>;" - "2000000: <%spellout-cardinal-masculine%%ordinal-esime>;" - "1000000000: miliard\u00AD>%%ordinal-esime-with-o>;" - "2000000000: <%spellout-cardinal-masculine%%ordinal-esime-with-o>;" - "1000000000000: bilione\u00AD>%%ordinal-esime>;" - "2000000000000: <%spellout-cardinal-masculine%%ordinal-esime>;" - "1000000000000000: biliard\u00AD>%%ordinal-esime-with-o>;" - "2000000000000000: <%spellout-cardinal-masculine%%ordinal-esime-with-o>;" + "1000: mille>%%ordinal-esime>;" + "2000: <%spellout-cardinal-masculine<[\u00ADmila>%%ordinal-esime>|\u00ADmillesime];" + "1000000: milione>%%ordinal-esime>;" + "2000000: <%spellout-cardinal-masculine<\u00ADmilione>%%ordinal-esime>;" + "1000000000: miliard>%%ordinal-esime-with-o>;" + "2000000000: <%spellout-cardinal-masculine<\u00ADmiliard>%%ordinal-esime-with-o>;" + "1000000000000: bilione>%%ordinal-esime>;" + "2000000000000: <%spellout-cardinal-masculine<\u00ADbilion>%%ordinal-esime>;" + "1000000000000000: biliard>%%ordinal-esime-with-o>;" + "2000000000000000: <%spellout-cardinal-masculine<\u00ADbiliard>%%ordinal-esime-with-o>;" "1000000000000000000: =#,##0=;" "%%ordinal-esime:" "0: sime;" @@ -477,7 +478,7 @@ it{ "7: \u00ADsettesime;" "8: \u00ADottesime;" "9: \u00ADnovesime;" - "10: =%spellout-ordinal-feminine-plural=;" + "10: \u00AD=%spellout-ordinal-feminine-plural=;" "%%ordinal-esime-with-i:" "0: esime;" "1: \u00ADunesime;" @@ -489,7 +490,7 @@ it{ "7: i\u00ADsettesime;" "8: \u00ADottesime;" "9: i\u00ADnovesime;" - "10: =%spellout-ordinal-feminine-plural=;" + "10: \u00AD=%spellout-ordinal-feminine-plural=;" "%%ordinal-esime-with-a:" "0: esime;" "1: \u00ADunesime;" @@ -501,7 +502,7 @@ it{ "7: a\u00ADsettesime;" "8: \u00ADottesime;" "9: a\u00ADnovesime;" - "10: =%spellout-ordinal-feminine-plural=;" + "10: \u00AD=%spellout-ordinal-feminine-plural=;" "%%ordinal-esime-with-o:" "0: esime;" "1: \u00ADunesime;" diff --git a/icu4c/source/data/rbnf/km.txt b/icu4c/source/data/rbnf/km.txt index acdae6dd8087..038aca171d15 100644 --- a/icu4c/source/data/rbnf/km.txt +++ b/icu4c/source/data/rbnf/km.txt @@ -9,8 +9,6 @@ km{ "0: \u1791\u17B8=#,##0=;" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << '\u200B' << '\u00AD';" "%spellout-numbering-year:" "0: =%spellout-numbering=;" "%spellout-numbering:" diff --git a/icu4c/source/data/rbnf/mk.txt b/icu4c/source/data/rbnf/mk.txt index 8295b56acda9..3f7e6fbd9265 100644 --- a/icu4c/source/data/rbnf/mk.txt +++ b/icu4c/source/data/rbnf/mk.txt @@ -4,8 +4,6 @@ mk{ RBNFRules{ SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-numbering=;" diff --git a/icu4c/source/data/rbnf/mt.txt b/icu4c/source/data/rbnf/mt.txt index d8f76a89e613..89d7a0094aed 100644 --- a/icu4c/source/data/rbnf/mt.txt +++ b/icu4c/source/data/rbnf/mt.txt @@ -25,12 +25,8 @@ mt{ "3600/60: <#,##0<:>>>;" "%duration:" "0: =%in-numerals=;" - "%%lenient-parse:" - "& ':' = '.' = ' ' = '-';" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-numbering=;" diff --git a/icu4c/source/data/rbnf/no.txt b/icu4c/source/data/rbnf/no.txt index 7d7451d38f73..2ade999ebcd0 100644 --- a/icu4c/source/data/rbnf/no.txt +++ b/icu4c/source/data/rbnf/no.txt @@ -4,8 +4,6 @@ no{ RBNFRules{ SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "-x: minus >>;" "x.x: =0.0=;" diff --git a/icu4c/source/data/rbnf/pt.txt b/icu4c/source/data/rbnf/pt.txt index 827fa45e51eb..3615448b6ec0 100644 --- a/icu4c/source/data/rbnf/pt.txt +++ b/icu4c/source/data/rbnf/pt.txt @@ -14,8 +14,6 @@ pt{ "0: =%digits-ordinal-masculine=;" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-numbering=;" diff --git a/icu4c/source/data/rbnf/pt_PT.txt b/icu4c/source/data/rbnf/pt_PT.txt index 42ac8a417e87..9c017c38a7f2 100644 --- a/icu4c/source/data/rbnf/pt_PT.txt +++ b/icu4c/source/data/rbnf/pt_PT.txt @@ -4,8 +4,6 @@ pt_PT{ RBNFRules{ SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-numbering=;" diff --git a/icu4c/source/data/rbnf/ru.txt b/icu4c/source/data/rbnf/ru.txt index 7e3612b13ed0..aaaa540b5eae 100644 --- a/icu4c/source/data/rbnf/ru.txt +++ b/icu4c/source/data/rbnf/ru.txt @@ -97,8 +97,6 @@ ru{ "0: =%digits-ordinal-plural-instrumental=;" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-ordinal-masculine-genitive=;" diff --git a/icu4c/source/data/rbnf/sr.txt b/icu4c/source/data/rbnf/sr.txt index 5ca0052b1d21..ebe42f70d17d 100644 --- a/icu4c/source/data/rbnf/sr.txt +++ b/icu4c/source/data/rbnf/sr.txt @@ -4,8 +4,6 @@ sr{ RBNFRules{ SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-ordinal-feminine=;" diff --git a/icu4c/source/data/rbnf/sv.txt b/icu4c/source/data/rbnf/sv.txt index 27a4a7af8cfd..8b482c3629d0 100644 --- a/icu4c/source/data/rbnf/sv.txt +++ b/icu4c/source/data/rbnf/sv.txt @@ -18,8 +18,6 @@ sv{ "0: =%digits-ordinal-feminine=;" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "-x: minus >>;" "x.x: =0.0=;" diff --git a/icu4c/source/data/rbnf/uk.txt b/icu4c/source/data/rbnf/uk.txt index 605376c65e0d..7e235ff195cf 100644 --- a/icu4c/source/data/rbnf/uk.txt +++ b/icu4c/source/data/rbnf/uk.txt @@ -17,8 +17,6 @@ uk{ "0: =#,##0=-$(ordinal,few{\u044F}other{\u0430})$;" } SpelloutRules{ - "%%lenient-parse:" - "&[last primary ignorable ] << ' ' << ',' << '-' << '\u00AD';" "%spellout-numbering-year:" "x.x: =0.0=;" "0: =%spellout-numbering=;" diff --git a/icu4c/source/data/xml/rbnf/be.xml b/icu4c/source/data/xml/rbnf/be.xml deleted file mode 100644 index 1e0c6a83f66f..000000000000 --- a/icu4c/source/data/xml/rbnf/be.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/data/xml/rbnf/bg.xml b/icu4c/source/data/xml/rbnf/bg.xml deleted file mode 100644 index 6f0751780657..000000000000 --- a/icu4c/source/data/xml/rbnf/bg.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/data/xml/rbnf/ca.xml b/icu4c/source/data/xml/rbnf/ca.xml deleted file mode 100644 index 1fd1f0947f1b..000000000000 --- a/icu4c/source/data/xml/rbnf/ca.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/data/xml/rbnf/cy.xml b/icu4c/source/data/xml/rbnf/cy.xml deleted file mode 100644 index c2a057719f2d..000000000000 --- a/icu4c/source/data/xml/rbnf/cy.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/data/xml/rbnf/da.xml b/icu4c/source/data/xml/rbnf/da.xml deleted file mode 100644 index 8fe28c87a8d4..000000000000 --- a/icu4c/source/data/xml/rbnf/da.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/data/xml/rbnf/de.xml b/icu4c/source/data/xml/rbnf/de.xml index 489a5aee3575..e771ca56aee1 100644 --- a/icu4c/source/data/xml/rbnf/de.xml +++ b/icu4c/source/data/xml/rbnf/de.xml @@ -14,7 +14,7 @@ diff --git a/icu4c/source/data/xml/rbnf/en.xml b/icu4c/source/data/xml/rbnf/en.xml index 9d96813e3969..72b869860abd 100644 --- a/icu4c/source/data/xml/rbnf/en.xml +++ b/icu4c/source/data/xml/rbnf/en.xml @@ -34,14 +34,6 @@ 3600/60: <#,##0<:>>>; %duration: 0: =%in-numerals=; -%%lenient-parse: -& ':' = '.' = ' ' = '-'; -]]> - - - diff --git a/icu4c/source/data/xml/rbnf/fo.xml b/icu4c/source/data/xml/rbnf/fo.xml deleted file mode 100644 index 461fc3280e59..000000000000 --- a/icu4c/source/data/xml/rbnf/fo.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/data/xml/rbnf/ga.xml b/icu4c/source/data/xml/rbnf/ga.xml index 4bd9d357e14a..c8e7caa1d875 100644 --- a/icu4c/source/data/xml/rbnf/ga.xml +++ b/icu4c/source/data/xml/rbnf/ga.xml @@ -51,8 +51,6 @@ 3600/60: <#,##0<:>>>; %duration: 0: =%in-numerals=; -%%lenient-parse: -& ':' = '.' = ' ' = '-'; ]]> diff --git a/icu4c/source/data/xml/rbnf/is.xml b/icu4c/source/data/xml/rbnf/is.xml deleted file mode 100644 index 0bc1b5cb352c..000000000000 --- a/icu4c/source/data/xml/rbnf/is.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/data/xml/rbnf/mk.xml b/icu4c/source/data/xml/rbnf/mk.xml deleted file mode 100644 index aa1177de4de8..000000000000 --- a/icu4c/source/data/xml/rbnf/mk.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/data/xml/rbnf/mt.xml b/icu4c/source/data/xml/rbnf/mt.xml index 4fdd93f0d1bb..50c6a69d7ab2 100644 --- a/icu4c/source/data/xml/rbnf/mt.xml +++ b/icu4c/source/data/xml/rbnf/mt.xml @@ -35,8 +35,6 @@ 3600/60: <#,##0<:>>>; %duration: 0: =%in-numerals=; -%%lenient-parse: -& ':' = '.' = ' ' = '-'; ]]> diff --git a/icu4c/source/data/xml/rbnf/no.xml b/icu4c/source/data/xml/rbnf/no.xml deleted file mode 100644 index 3c56e353e33a..000000000000 --- a/icu4c/source/data/xml/rbnf/no.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/data/xml/rbnf/ru.xml b/icu4c/source/data/xml/rbnf/ru.xml deleted file mode 100644 index c572a7d4d629..000000000000 --- a/icu4c/source/data/xml/rbnf/ru.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/data/xml/rbnf/sr.xml b/icu4c/source/data/xml/rbnf/sr.xml deleted file mode 100644 index 43333425fd72..000000000000 --- a/icu4c/source/data/xml/rbnf/sr.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/data/xml/rbnf/uk.xml b/icu4c/source/data/xml/rbnf/uk.xml deleted file mode 100644 index ae52b4b06236..000000000000 --- a/icu4c/source/data/xml/rbnf/uk.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - diff --git a/icu4c/source/i18n/nfrule.cpp b/icu4c/source/i18n/nfrule.cpp index e947823e318e..0078159af82b 100644 --- a/icu4c/source/i18n/nfrule.cpp +++ b/icu4c/source/i18n/nfrule.cpp @@ -26,6 +26,7 @@ #include "unicode/upluralrules.h" #include "unicode/coleitr.h" #include "unicode/uchar.h" +#include "unicode/normalizer2.h" #include "nfrs.h" #include "nfrlist.h" #include "nfsubs.h" @@ -34,6 +35,13 @@ U_NAMESPACE_BEGIN +// Characters that lenient parsing treats as ignorable separators in prefixLength. +// Zs = space separators, Pd = dash punctuation, Cf = format characters (soft hyphen, ZWNJ, etc.) +// Plus comma, and period which %%lenient-parse rules historically treated as equivalent. +static inline UBool isLenientSeparator(char16_t c) { + return (U_GET_GC_MASK(c) & (U_GC_ZS_MASK | U_GC_PD_MASK | U_GC_CF_MASK)) || c == u',' || c == u'.'; +} + NFRule::NFRule(const RuleBasedNumberFormat* _rbnf, const UnicodeString &_ruleText, UErrorCode &status) : ruleText(_ruleText) , formatter(_rbnf) @@ -1255,11 +1263,7 @@ NFRule::matchToDelimiter(const UnicodeString& text, subText.setTo(text, 0, dPos); if (!subText.isEmpty()) { UBool success = sub->doParse(subText, tempPP, _baseValue, upperBound, -#if UCONFIG_NO_COLLATION - false, -#else formatter->isLenient(), -#endif nonNumericalExecutedRuleMask, recursionCount, result); @@ -1317,11 +1321,7 @@ NFRule::matchToDelimiter(const UnicodeString& text, // try to match the whole string against the substitution UBool success = sub->doParse(text, tempPP, _baseValue, upperBound, -#if UCONFIG_NO_COLLATION - false, -#else formatter->isLenient(), -#endif nonNumericalExecutedRuleMask, recursionCount, result); @@ -1368,12 +1368,104 @@ NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix, UErr return 0; } -#if !UCONFIG_NO_COLLATION - // go through all this grief if we're in lenient-parse mode + // Check if non-lenient rule finds the text before call lenient parsing + if (str.startsWith(prefix)) { + return prefix.length(); + } + if (formatter->isLenient()) { - // Check if non-lenient rule finds the text before call lenient parsing - if (str.startsWith(prefix)) { - return prefix.length(); + // In lenient-parse mode, walk both strings simultaneously: + // skip separator characters in both, and compare the rest case-insensitively. + // NFC normalization is applied incrementally to handle NFC/NFD differences + // (e.g., U+00E9 vs U+0065 U+0301). NFC is used instead of NFD to + // avoid decomposing Hangul syllables into Jamo (which would create false + // prefix matches) and to preserve correct Turkish dotted uppercase i case folding behavior. + UErrorCode err = U_ZERO_ERROR; +#if !UCONFIG_NO_NORMALIZATION + const Normalizer2 *nfc = Normalizer2::getNFCInstance(err); + if (U_SUCCESS(err)) { + // NFC-normalize the prefix up front (it's short rule text). + UnicodeString nfcPrefix; + nfc->normalize(prefix, nfcPrefix, err); + if (U_SUCCESS(err)) { + int32_t strIdx = 0; // position in original str + int32_t prefixIdx = 0; + int32_t strLen = str.length(); + int32_t nfcPrefixLen = nfcPrefix.length(); + UBool matched = true; + + // Buffer for the NFC of the current normalization segment from str. + // We normalize str segments on the fly to avoid normalizing the entire string. + UnicodeString strSeg, strNfc; + int32_t strNfcIdx = 0; + int32_t strNfcLen = 0; + + UBool prefixIsAllSeparators = true; + for (int32_t i = 0; i < nfcPrefixLen; ++i) { + if (!isLenientSeparator(nfcPrefix.charAt(i))) { + prefixIsAllSeparators = false; + break; + } + } + while (prefixIdx < nfcPrefixLen) { + // Skip separators in str only when the NFC buffer is exhausted. + // Separators are NFC-inert and always appear at segment boundaries. + int32_t strSepCount = 0; + while (strNfcIdx >= strNfcLen && strIdx < strLen && isLenientSeparator(str.charAt(strIdx))) { + ++strIdx; + ++strSepCount; + } + while (prefixIdx < nfcPrefixLen && isLenientSeparator(nfcPrefix.charAt(prefixIdx))) { + ++prefixIdx; + } + if (prefixIsAllSeparators && prefixIdx >= nfcPrefixLen && strSepCount == 0) { + matched = false; + break; + } + if (prefixIdx >= nfcPrefixLen) { + break; + } + + // Get the next NFC code unit from str. + if (strNfcIdx >= strNfcLen) { + if (strIdx >= strLen) { + matched = false; + break; + } + // Read the next normalization segment from str up to the next NFC boundary. + strSeg.remove(); + do { + UChar32 cp = str.char32At(strIdx); + strSeg.append(cp); + strIdx += U16_LENGTH(cp); + } while (strIdx < strLen && !nfc->hasBoundaryBefore(str.char32At(strIdx))); + + nfc->normalize(strSeg, strNfc, err); + if (U_FAILURE(err)) { + break; + } + strNfcIdx = 0; + strNfcLen = strNfc.length(); + } + + if (u_foldCase(strNfc.charAt(strNfcIdx++), formatter->caseFoldOption) != u_foldCase(nfcPrefix.charAt(prefixIdx), formatter->caseFoldOption)) { + matched = false; + break; + } + ++prefixIdx; + } + if (matched) { + return strIdx; + } + } + } +#endif + + // go through all this grief if we're in lenient-parse mode +#if !UCONFIG_NO_COLLATION + if (formatter->lenientParseRules == nullptr) { + // Nothing customized. Don't go further. + return 0; } // get the formatter's collator and use it to create two // collation element iterators, one over the target string @@ -1395,7 +1487,7 @@ NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix, UErr return 0; } - UErrorCode err = U_ZERO_ERROR; + err = U_ZERO_ERROR; // The original code was problematic. Consider this match: // prefix = "fifty-" @@ -1472,65 +1564,9 @@ NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix, UErr fprintf(stderr, "prefix length: %d\n", result); #endif return result; -#if 0 - //---------------------------------------------------------------- - // JDK 1.2-specific API call - // return strIter.getOffset(); - //---------------------------------------------------------------- - // JDK 1.1 HACK (take out for 1.2-specific code) - - // if we make it to here, we have a successful match. Now we - // have to find out HOW MANY characters from the target string - // matched the prefix (there isn't necessarily a one-to-one - // mapping between collation elements and characters). - // In JDK 1.2, there's a simple getOffset() call we can use. - // In JDK 1.1, on the other hand, we have to go through some - // ugly contortions. First, use the collator to compare the - // same number of characters from the prefix and target string. - // If they're equal, we're done. - collator->setStrength(Collator::PRIMARY); - if (str.length() >= prefix.length()) { - UnicodeString temp; - temp.setTo(str, 0, prefix.length()); - if (collator->equals(temp, prefix)) { -#ifdef RBNF_DEBUG - fprintf(stderr, "returning: %d\n", prefix.length()); #endif - return prefix.length(); - } - } - - // if they're not equal, then we have to compare successively - // larger and larger substrings of the target string until we - // get to one that matches the prefix. At that point, we know - // how many characters matched the prefix, and we can return. - int32_t p = 1; - while (p <= str.length()) { - UnicodeString temp; - temp.setTo(str, 0, p); - if (collator->equals(temp, prefix)) { - return p; - } else { - ++p; - } - } - - // SHOULD NEVER GET HERE!!! - return 0; - //---------------------------------------------------------------- -#endif - - // If lenient parsing is turned off, forget all that crap above. - // Just use String.startsWith() and be done with it. - } else -#endif - { - if (str.startsWith(prefix)) { - return prefix.length(); - } else { - return 0; - } - } + } + return 0; } /** @@ -1649,45 +1685,10 @@ NFRule::findTextLenient(const UnicodeString& str, * ignorable at the primary-order level. false otherwise. */ UBool -NFRule::allIgnorable(const UnicodeString& str, UErrorCode& status) const +NFRule::allIgnorable(const UnicodeString& str, UErrorCode& /*status*/) const { // if the string is empty, we can just return true - if (str.length() == 0) { - return true; - } - -#if !UCONFIG_NO_COLLATION - // if lenient parsing is turned on, walk through the string with - // a collation element iterator and make sure each collation - // element is 0 (ignorable) at the primary level - if (formatter->isLenient()) { - const RuleBasedCollator* collator = formatter->getCollator(); - if (collator == nullptr) { - status = U_MEMORY_ALLOCATION_ERROR; - return false; - } - LocalPointer iter(collator->createCollationElementIterator(str)); - - // Memory allocation error check. - if (iter.isNull()) { - status = U_MEMORY_ALLOCATION_ERROR; - return false; - } - - UErrorCode err = U_ZERO_ERROR; - int32_t o = iter->next(err); - while (o != CollationElementIterator::NULLORDER - && CollationElementIterator::primaryOrder(o) == 0) { - o = iter->next(err); - } - - return o == CollationElementIterator::NULLORDER; - } -#endif - - // if lenient parsing is turned off, there is no such thing as - // an ignorable character: return true only if the string is empty - return false; + return str.length() == 0; } void diff --git a/icu4c/source/i18n/rbnf.cpp b/icu4c/source/i18n/rbnf.cpp index a283efb0247f..66cc4ceb9b38 100644 --- a/icu4c/source/i18n/rbnf.cpp +++ b/icu4c/source/i18n/rbnf.cpp @@ -785,6 +785,10 @@ RuleBasedNumberFormat::operator=(const RuleBasedNumberFormat& rhs) setDefaultRuleSet(rhs.getDefaultRuleSetName(), status); setRoundingMode(rhs.getRoundingMode()); + if (lenient) { + initializeCollator(status); + } + capitalizationInfoSet = rhs.capitalizationInfoSet; capitalizationForUIListMenu = rhs.capitalizationForUIListMenu; capitalizationForStandAlone = rhs.capitalizationForStandAlone; @@ -1202,7 +1206,11 @@ RuleBasedNumberFormat::adjustForCapitalizationContext(int32_t startPos, (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) { // titlecase first word of currentResult, here use sentence iterator unlike current implementations // in LocaleDisplayNamesImpl::adjustForUsageAndContext and RelativeDateFormat::format - currentResult.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT); + // Clone the break iterator to avoid mutating it in a const method (thread safety). + LocalPointer iter(capitalizationBrkIter->clone()); + if (iter.isValid()) { + currentResult.toTitle(iter.getAlias(), locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT); + } } } #endif @@ -1264,21 +1272,23 @@ RuleBasedNumberFormat::parse(const UnicodeString& text, } } -#if !UCONFIG_NO_COLLATION - void RuleBasedNumberFormat::setLenient(UBool enabled) { lenient = enabled; +#if !UCONFIG_NO_COLLATION if (!enabled && collator) { delete collator; collator = nullptr; + } else if (enabled && collator == nullptr) { + // Eagerly initialize the collator so that getCollator() is thread-safe. + UErrorCode status = U_ZERO_ERROR; + initializeCollator(status); } -} - #endif +} -void +void RuleBasedNumberFormat::setDefaultRuleSet(const UnicodeString& ruleSetName, UErrorCode& status) { if (U_SUCCESS(status)) { if (ruleSetName.isEmpty()) { @@ -1355,6 +1365,11 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali return; } + // Use Turkic case folding for Turkish and Azerbaijani locales. + const char* lang = locale.getLanguage(); + caseFoldOption = (uprv_strcmp(lang, "tr") == 0 || uprv_strcmp(lang, "az") == 0) + ? U_FOLD_CASE_EXCLUDE_SPECIAL_I : U_FOLD_CASE_DEFAULT; + initializeDecimalFormatSymbols(status); initializeDefaultInfinityRule(status); initializeDefaultNaNRule(status); @@ -1686,55 +1701,52 @@ RuleBasedNumberFormat::dispose() //----------------------------------------------------------------------- /** - * Returns the collator to use for lenient parsing. The collator is lazily created: - * this function creates it the first time it's called. - * @return The collator to use for lenient parsing, or null if lenient parsing - * is turned off. -*/ -const RuleBasedCollator* -RuleBasedNumberFormat::getCollator() const + * Initializes the collator for lenient parsing. Must be called from + * non-const methods (setLenient, operator=) so that getCollator() can + * be thread-safe. + */ +void +RuleBasedNumberFormat::initializeCollator(UErrorCode &status) { #if !UCONFIG_NO_COLLATION - if (!fRuleSets) { - return nullptr; + if (collator != nullptr || !fRuleSets) { + return; } - // lazy-evaluate the collator - if (collator == nullptr && lenient) { - // create a default collator based on the formatter's locale, - // then pull out that collator's rules, append any additional - // rules specified in the description, and create a _new_ - // collator based on the combination of those rules - - UErrorCode status = U_ZERO_ERROR; + Collator* temp = Collator::createInstance(locale, status); + RuleBasedCollator* newCollator; + if (U_SUCCESS(status) && (newCollator = dynamic_cast(temp)) != nullptr) { + if (lenientParseRules) { + UnicodeString rules(newCollator->getRules()); + rules.append(*lenientParseRules); - Collator* temp = Collator::createInstance(locale, status); - RuleBasedCollator* newCollator; - if (U_SUCCESS(status) && (newCollator = dynamic_cast(temp)) != nullptr) { - if (lenientParseRules) { - UnicodeString rules(newCollator->getRules()); - rules.append(*lenientParseRules); - - newCollator = new RuleBasedCollator(rules, status); - // Exit if newCollator could not be created. - if (newCollator == nullptr) { - return nullptr; - } - } else { - temp = nullptr; - } - if (U_SUCCESS(status)) { - newCollator->setAttribute(UCOL_DECOMPOSITION_MODE, UCOL_ON, status); - // cast away const - const_cast(this)->collator = newCollator; - } else { - delete newCollator; + newCollator = new RuleBasedCollator(rules, status); + // Exit if newCollator could not be created. + if (newCollator == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return; } + } else { + temp = nullptr; + } + if (U_SUCCESS(status)) { + newCollator->setAttribute(UCOL_DECOMPOSITION_MODE, UCOL_ON, status); + collator = newCollator; + } else { + delete newCollator; } - delete temp; } + delete temp; #endif +} +/** + * Returns the collator to use for lenient parsing, or null if lenient parsing + * is turned off. +*/ +const RuleBasedCollator* +RuleBasedNumberFormat::getCollator() const +{ // if lenient-parse mode is off, this will be null // (see setLenientParseMode()) return collator; diff --git a/icu4c/source/i18n/unicode/rbnf.h b/icu4c/source/i18n/unicode/rbnf.h index d730dcf3a087..2f30e51b2d17 100644 --- a/icu4c/source/i18n/unicode/rbnf.h +++ b/icu4c/source/i18n/unicode/rbnf.h @@ -985,8 +985,6 @@ class U_I18N_API_CLASS RuleBasedNumberFormat : public NumberFormat { Formattable& result, ParsePosition& parsePosition) const override; -#if !UCONFIG_NO_COLLATION - /** * Turns lenient parse mode on and off. * @@ -1031,8 +1029,6 @@ class U_I18N_API_CLASS RuleBasedNumberFormat : public NumberFormat { */ U_I18N_API virtual inline UBool isLenient() const override; -#endif - /** * Override the default rule set to use. If ruleSetName is null, reset * to the initial default rule set. If the rule set is not a public rule set name, @@ -1135,6 +1131,7 @@ class U_I18N_API_CLASS RuleBasedNumberFormat : public NumberFormat { friend class FractionalPartSubstitution; inline NFRuleSet * getDefaultRuleSet() const; + void initializeCollator(UErrorCode &status); const RuleBasedCollator * getCollator() const; DecimalFormatSymbols * initializeDecimalFormatSymbols(UErrorCode &status); const DecimalFormatSymbols * getDecimalFormatSymbols() const; @@ -1160,6 +1157,7 @@ class U_I18N_API_CLASS RuleBasedNumberFormat : public NumberFormat { ERoundingMode fRoundingMode { ERoundingMode::kRoundUnnecessary }; UBool lenient { }; UBool unparseable { }; + uint8_t caseFoldOption { }; UnicodeString* lenientParseRules { }; LocalizationInfo* localizations { }; UnicodeString originalDescription; @@ -1171,15 +1169,11 @@ class U_I18N_API_CLASS RuleBasedNumberFormat : public NumberFormat { // --------------- -#if !UCONFIG_NO_COLLATION - inline UBool RuleBasedNumberFormat::isLenient() const { return lenient; } -#endif - inline NFRuleSet* RuleBasedNumberFormat::getDefaultRuleSet() const { return defaultRuleSet; diff --git a/icu4c/source/test/intltest/itrbnf.cpp b/icu4c/source/test/intltest/itrbnf.cpp index 1633055c9640..ad7ad8f8d266 100644 --- a/icu4c/source/test/intltest/itrbnf.cpp +++ b/icu4c/source/test/intltest/itrbnf.cpp @@ -89,6 +89,7 @@ void IntlTestRBNF::runIndexedTest(int32_t index, UBool exec, const char* &name, TESTCASE(37, TestUnparseableConflictingSubstitutions); TESTCASE(38, TestAmbiguousDelimiter); TESTCASE(39, TestDividedByZero); + TESTCASE(40, TestTurkishSpellout); #else TESTCASE(0, TestRBNFDisabled); #endif @@ -258,7 +259,6 @@ IntlTestRBNF::TestAPI() { } } -#if !UCONFIG_NO_COLLATION // test ruleset names { logln("Testing getNumberOfRuleSetNames, getRuleSetName and format using rule set names"); @@ -319,7 +319,6 @@ IntlTestRBNF::TestAPI() { } status = U_ZERO_ERROR; } -#endif // test API UnicodeString expected("four point five",""); @@ -1183,7 +1182,6 @@ IntlTestRBNF::TestEnglishSpellout() doTest(formatter, testData, true); -#if !UCONFIG_NO_COLLATION formatter->setLenient(true); static const char* lpTestData[][2] = { { "fifty-7", "57" }, @@ -1195,7 +1193,6 @@ IntlTestRBNF::TestEnglishSpellout() { nullptr, nullptr} }; doLenientParseTest(formatter, lpTestData); -#endif } delete formatter; } @@ -1270,14 +1267,12 @@ IntlTestRBNF::TestDurations() }; doTest(formatter, fractionalTestData, false); -#if !UCONFIG_NO_COLLATION formatter->setLenient(true); static const char* lpTestData[][2] = { { "2-51-33", "10,293" }, { nullptr, nullptr} }; doLenientParseTest(formatter, lpTestData); -#endif } delete formatter; } @@ -1391,8 +1386,24 @@ IntlTestRBNF::TestSpanishSpellout() { "234.567", "doscientos treinta y cuatro coma cinco seis siete" }, { nullptr, nullptr} }; - + doTest(formatter, testData, true); + + formatter->setLenient(true); + static const char* lpTestData[][2] = { + // NFD form of "dieciséis": s + e + combining acute + i + s + { "diecise\\u0301is", "16" }, + // Accent missing. + { "dieciseis", "16" }, + // Mixed case with NFD accent + { "DIECISE\\u0301IS", "16" }, + // NFD form of "veintiséis" + { "veintise\\u0301is", "26" }, + // Standard NFC form should still work + { "diecis\\u00e9is", "16" }, + { nullptr, nullptr} + }; + doLenientParseTest(formatter, lpTestData); } delete formatter; } @@ -1439,15 +1450,15 @@ IntlTestRBNF::TestFrenchSpellout() doTest(formatter, testData, true); -#if !UCONFIG_NO_COLLATION formatter->setLenient(true); static const char* lpTestData[][2] = { { "trente-et-un", "31" }, + { "trente et un", "31" }, + { "TRENTE ET UN", "31" }, { "un cent quatre vingt dix huit", "198" }, { nullptr, nullptr} }; doLenientParseTest(formatter, lpTestData); -#endif } delete formatter; } @@ -2053,7 +2064,6 @@ IntlTestRBNF::TestAllLocales() break; } -#if !UCONFIG_NO_COLLATION for (unsigned int numidx = 0; numidx < UPRV_LENGTHOF(numbers); numidx++) { double n = numbers[numidx]; UnicodeString str; @@ -2113,7 +2123,6 @@ IntlTestRBNF::TestAllLocales() } } } -#endif delete f; } } @@ -2827,6 +2836,36 @@ IntlTestRBNF::TestDividedByZero() { assertEquals("base is too large", U_NUMBER_ARG_OUTOFBOUNDS_ERROR, status); } +void +IntlTestRBNF::TestTurkishSpellout() { + UErrorCode status = U_ZERO_ERROR; + RuleBasedNumberFormat formatter(URBNF_SPELLOUT, Locale("tr"), status); + + if (U_FAILURE(status)) { + errcheckln(status, "FAIL: could not construct formatter - %s", u_errorName(status)); + } else { + static const char* const testData[][2] = { + { "2", "iki" }, + { "6", "alt\\u0131" }, + { nullptr, nullptr} + }; + + doTest(&formatter, testData, true); + + formatter.setLenient(true); + static const char* lpTestData[][2] = { + { "iki", "2" }, + { "iK\\u0130", "2" }, + { "\\u0130ki", "2" }, + { "\\u0130K\\u0130", "2" }, + { "alt\\u0131", "6" }, + { "ALTI", "6" }, + { nullptr, nullptr} + }; + doLenientParseTest(&formatter, lpTestData); + } +} + /* U_HAVE_RBNF */ #else diff --git a/icu4c/source/test/intltest/itrbnf.h b/icu4c/source/test/intltest/itrbnf.h index d36dbb02ffa3..afe5bc9291b8 100644 --- a/icu4c/source/test/intltest/itrbnf.h +++ b/icu4c/source/test/intltest/itrbnf.h @@ -170,6 +170,7 @@ class IntlTestRBNF : public IntlTest { void TestUnparseableConflictingSubstitutions(); void TestAmbiguousDelimiter(); void TestDividedByZero(); + void TestTurkishSpellout(); protected: virtual void doTest(RuleBasedNumberFormat* formatter, const char* const testData[][2], UBool testParsing); diff --git a/icu4j/main/common_tests/src/test/java/com/ibm/icu/dev/test/format/RbnfTest.java b/icu4j/main/common_tests/src/test/java/com/ibm/icu/dev/test/format/RbnfTest.java index c67b18b61f46..4b5535583286 100644 --- a/icu4j/main/common_tests/src/test/java/com/ibm/icu/dev/test/format/RbnfTest.java +++ b/icu4j/main/common_tests/src/test/java/com/ibm/icu/dev/test/format/RbnfTest.java @@ -442,6 +442,21 @@ public void TestSpanishSpellout() { }; doTest(formatter, testData, true); + + String[][] lpTestData = { + // NFD form of "dieciséis": s + e + combining acute + i + s + {"diecise\u0301is", "16"}, + // Accent missing. + {"dieciseis", "16"}, + // Mixed case with NFD accent + {"DIECISE\u0301IS", "16"}, + // NFD form of "veintiséis" + {"veintise\u0301is", "26"}, + // Standard NFC form should still work + {"diecis\u00e9is", "16"}, + }; + + doParsingTest(formatter, lpTestData, true); } /** Perform a simple spot check on the French spellout rules */ @@ -485,6 +500,8 @@ public void TestFrenchSpellout() { String[][] testDataLenient = { {"trente-et-un", "31"}, + {"trente et un", "31"}, + {"TRENTE ET UN", "31"}, {"un cent quatre vingt dix huit", "198"}, }; @@ -2304,4 +2321,29 @@ public void TestAmbiguousDelimiter() throws ParseException { errln("parse got " + result.longValue() + " instead of 10000000"); } } + + @Test + public void TestTurkishSpellout() { + Locale locale = new Locale("tr"); + RuleBasedNumberFormat formatter = + new RuleBasedNumberFormat(locale, RuleBasedNumberFormat.SPELLOUT); + + String[][] testData = { + {"2", "iki"}, + {"6", "alt\u0131"}, + }; + + doTest(formatter, testData, true); + + String[][] lpTestData = { + {"iki", "2"}, + {"iK\u0130", "2"}, + {"\u0130ki", "2"}, + {"\u0130K\u0130", "2"}, + {"alt\u0131", "6"}, + {"ALTI", "6"}, + }; + + doParsingTest(formatter, lpTestData, true); + } } diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/text/NFRule.java b/icu4j/main/core/src/main/java/com/ibm/icu/text/NFRule.java index 09a0feee9032..2d633503344a 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/text/NFRule.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/text/NFRule.java @@ -9,6 +9,7 @@ package com.ibm.icu.text; import com.ibm.icu.impl.PatternProps; +import com.ibm.icu.lang.UCharacter; import java.text.FieldPosition; import java.text.ParsePosition; import java.util.List; @@ -1247,6 +1248,20 @@ private Number matchToDelimiter( } } + /** + * Characters that lenient parsing treats as ignorable separators in prefixLength. Zs = space + * separators, Pd = dash punctuation, Cf = format characters (soft hyphen, ZWNJ, etc.) Plus + * comma and period which lenient-parse rules historically treated as equivalent. + */ + private static boolean isLenientSeparator(char c) { + int type = UCharacter.getType(c); + return type == UCharacter.SPACE_SEPARATOR + || type == UCharacter.DASH_PUNCTUATION + || type == UCharacter.FORMAT + || c == ',' + || c == '.'; + } + /** * Used by stripPrefix() to match characters. If lenient parse mode is off, this just calls * startsWith(). If lenient parse mode is on, this function uses CollationElementIterators to @@ -1266,20 +1281,107 @@ private int prefixLength(String str, String prefix) { return 0; } - RbnfLenientScanner scanner = formatter.getLenientScanner(); - if (scanner != null) { - // Check if non-lenient rule finds the text before call lenient parsing - if (str.startsWith(prefix)) { - return prefix.length(); - } - return scanner.prefixLength(str, prefix); - } - - // If lenient parsing is turned off, forget all that crap above. - // Just use String.startsWith() and be done with it. + // Check if non-lenient rule finds the text before call lenient parsing if (str.startsWith(prefix)) { return prefix.length(); } + + if (formatter.lenientParseEnabled()) { + // In lenient-parse mode, walk both strings simultaneously: + // skip separator characters in both, and compare the rest case-insensitively. + // NFC normalization is applied incrementally to handle NFC/NFD differences + // (e.g., U+00E9 vs U+0065 U+0301). NFC is used instead of NFD to + // avoid decomposing Hangul syllables into Jamo (which would create false + // prefix matches) and to preserve correct Turkish dotted uppercase i case folding + // behavior. + Normalizer2 nfc = Normalizer2.getNFCInstance(); + // NFC-normalize the prefix up front (it's short rule text). + String nfcPrefix = nfc.normalize(prefix); + int strLen = str.length(); + int nfcPrefixLen = nfcPrefix.length(); + int strIdx = 0; + int prefixIdx = 0; + boolean matched = true; + + // Buffer for the NFC of the current normalization segment from str. + // We normalize str segments on the fly to avoid normalizing the entire string. + StringBuilder strSeg = new StringBuilder(); + String strNfc = ""; + int strNfcIdx = 0; + int strNfcLen = 0; + + // Check if the prefix consists entirely of separator characters. + // If so, require that the str also has at least one separator. + boolean prefixIsAllSeparators = true; + for (int i = 0; i < nfcPrefixLen; ++i) { + if (!isLenientSeparator(nfcPrefix.charAt(i))) { + prefixIsAllSeparators = false; + break; + } + } + while (prefixIdx < nfcPrefixLen) { + // Skip separators in str only when the NFC buffer is exhausted. + // Separators are NFC-inert and always appear at segment boundaries. + int strSepCount = 0; + while (strNfcIdx >= strNfcLen + && strIdx < strLen + && isLenientSeparator(str.charAt(strIdx))) { + ++strIdx; + ++strSepCount; + } + while (prefixIdx < nfcPrefixLen + && isLenientSeparator(nfcPrefix.charAt(prefixIdx))) { + ++prefixIdx; + } + // If the prefix is entirely separators (e.g., " "), require + // at least one separator in str to match against. + if (prefixIsAllSeparators && prefixIdx >= nfcPrefixLen && strSepCount == 0) { + matched = false; + break; + } + if (prefixIdx >= nfcPrefixLen) { + break; + } + + // Get the next NFC code unit from str. + if (strNfcIdx >= strNfcLen) { + if (strIdx >= strLen) { + matched = false; + break; + } + // Read the next normalization segment from str up to the next NFC boundary. + strSeg.setLength(0); + do { + int cp = Character.codePointAt(str, strIdx); + strSeg.appendCodePoint(cp); + strIdx += Character.charCount(cp); + } while (strIdx < strLen + && !nfc.hasBoundaryBefore(Character.codePointAt(str, strIdx))); + + strNfc = nfc.normalize(strSeg); + strNfcIdx = 0; + strNfcLen = strNfc.length(); + } + + if (UCharacter.foldCase(strNfc.charAt(strNfcIdx++), formatter.caseFoldOption) + != UCharacter.foldCase( + nfcPrefix.charAt(prefixIdx), formatter.caseFoldOption)) { + matched = false; + break; + } + ++prefixIdx; + } + if (matched) { + return strIdx; + } + + // Fall back to the collator-based scanner for locale-specific equivalences + RbnfLenientScanner scanner = formatter.getLenientScanner(); + if (scanner != null) { + return scanner.prefixLength(str, prefix); + } + } + return 0; } @@ -1296,11 +1398,10 @@ private int prefixLength(String str, String prefix) { * necessarily the same as the length of "key") */ private int[] findText(String str, String key, PluralFormat pluralFormatKey, int startingAt) { - RbnfLenientScanner scanner = formatter.getLenientScanner(); if (pluralFormatKey != null) { FieldPosition position = new FieldPosition(NumberFormat.INTEGER_FIELD); position.setBeginIndex(startingAt); - pluralFormatKey.parseType(str, scanner, position); + pluralFormatKey.parseType(str, position); int start = position.getBeginIndex(); if (start >= 0) { int pluralRuleStart = ruleText.indexOf("$("); @@ -1318,15 +1419,22 @@ private int[] findText(String str, String key, PluralFormat pluralFormatKey, int return new int[] {-1, 0}; } - if (scanner != null) { + if (formatter.lenientParseEnabled()) { // Check if non-lenient rule finds the text before call lenient parsing - int[] pos = new int[] {str.indexOf(key, startingAt), key.length()}; - if (pos[0] >= 0) { - return pos; - } else { - // if lenient parsing is turned ON, we've got some work ahead of us - return scanner.findText(str, key, startingAt); + int pos = str.indexOf(key, startingAt); + if (pos >= 0) { + return new int[] {pos, key.length()}; } + + // Search by trying prefixLength at each position. + for (int p = startingAt; p < str.length(); ++p) { + int keyLen = prefixLength(str.substring(p), key); + if (keyLen != 0) { + return new int[] {p, keyLen}; + } + } + + return new int[] {-1, 0}; } // if lenient parsing is turned off, this is easy. Just call // String.indexOf() and we're done @@ -1341,12 +1449,7 @@ private int[] findText(String str, String key, PluralFormat pluralFormatKey, int * formatter's collator says are ignorable at the primary-order level. false otherwise. */ private boolean allIgnorable(String str) { - // if the string is empty, we can just return true - if (str == null || str.isEmpty()) { - return true; - } - RbnfLenientScanner scanner = formatter.getLenientScanner(); - return scanner != null && scanner.allIgnorable(str); + return str == null || str.isEmpty(); } public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) { diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/text/PluralFormat.java b/icu4j/main/core/src/main/java/com/ibm/icu/text/PluralFormat.java index 58a8974920bc..450f1b983680 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/text/PluralFormat.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/text/PluralFormat.java @@ -791,7 +791,7 @@ public Object parseObject(String source, ParsePosition pos) { * @return Returns the PluralRules type. For example, it could be "zero", "one", "two", "few", * "many" or "other") */ - /*package*/ String parseType(String source, RbnfLenientScanner scanner, FieldPosition pos) { + /*package*/ String parseType(String source, FieldPosition pos) { // If no pattern was applied, return null. if (msgPattern == null || msgPattern.countParts() == 0) { pos.setBeginIndex(-1); @@ -835,20 +835,7 @@ public Object parseObject(String source, ParsePosition pos) { } String currArg = pattern.substring(partStart.getLimit(), partLimit.getIndex()); - if (scanner != null) { - // Check if non-lenient rule finds the text before call lenient parsing - int tempPos = source.indexOf(currArg, startingAt); - if (tempPos >= 0) { - currMatchIndex = tempPos; - } else { - // If lenient parsing is turned ON, we've got some time consuming parsing ahead - // of us. - int[] scannerMatchResult = scanner.findText(source, currArg, startingAt); - currMatchIndex = scannerMatchResult[0]; - } - } else { - currMatchIndex = source.indexOf(currArg, startingAt); - } + currMatchIndex = source.indexOf(currArg, startingAt); if (currMatchIndex >= 0 && currMatchIndex >= matchedIndex && (matchedWord == null || currArg.length() > matchedWord.length())) { diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/text/RuleBasedNumberFormat.java b/icu4j/main/core/src/main/java/com/ibm/icu/text/RuleBasedNumberFormat.java index 0070a2247695..b958a7a9aaeb 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/text/RuleBasedNumberFormat.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/text/RuleBasedNumberFormat.java @@ -637,6 +637,12 @@ public class RuleBasedNumberFormat extends NumberFormat implements Cloneable { */ private boolean lenientParse = false; + /** + * Case folding option for lenient parsing. Uses Turkic case folding for Turkish and Azerbaijani + * locales. + */ + transient byte caseFoldOption = (byte) UCharacter.FOLD_CASE_DEFAULT; + /** * Specifies if one of the rules is unparseable. For example, there may be substitutions of the * same type in a rule. @@ -1356,6 +1362,11 @@ public Number parse(String text, ParsePosition parsePosition) { */ public void setLenientParseMode(boolean enabled) { lenientParse = enabled; + if (enabled) { + // Eagerly initialize the scanner provider so that getLenientScannerProvider() + // is thread-safe when called from parse(). + initializeLenientScannerProvider(); + } } /** @@ -1392,10 +1403,20 @@ public void setLenientScannerProvider(RbnfLenientScannerProvider scannerProvider * @stable ICU 4.4 */ public RbnfLenientScannerProvider getLenientScannerProvider() { - // there's a potential race condition if two threads try to set/get the scanner at - // the same time, but you get what you get, and you shouldn't be using this from - // multiple threads anyway. if (scannerProvider == null && lenientParse && !lookedForScanner) { + initializeLenientScannerProvider(); + } + + return scannerProvider; + } + + /** + * Attempts to instantiate the default lenient scanner provider. Called eagerly from + * setLenientParseMode() so that getLenientScannerProvider() does not need to perform lazy + * initialization from parse() (thread safety). + */ + private void initializeLenientScannerProvider() { + if (scannerProvider == null && !lookedForScanner) { try { lookedForScanner = true; Class cls = Class.forName("com.ibm.icu.impl.text.RbnfScannerProviderImpl"); @@ -1406,8 +1427,6 @@ public RbnfLenientScannerProvider getLenientScannerProvider() { // any failure, we just ignore and return null } } - - return scannerProvider; } /** @@ -1576,7 +1595,7 @@ NFRuleSet getDefaultRuleSet() { * @return The collator to use for lenient parsing, or null if lenient parsing is turned off. */ RbnfLenientScanner getLenientScanner() { - if (lenientParse) { + if (lenientParse && lenientParseRules != null && !lenientParseRules.isEmpty()) { RbnfLenientScannerProvider provider = getLenientScannerProvider(); if (provider != null) { return provider.get(locale, lenientParseRules); @@ -1696,6 +1715,14 @@ private static String extractSpecial(StringBuilder description, String specialNa private void init(String description, String[][] localizations) { initLocalizations(localizations); + // Use Turkic case folding for Turkish and Azerbaijani locales. + String lang = locale.getLanguage(); + caseFoldOption = + (byte) + (("tr".equals(lang) || "az".equals(lang)) + ? UCharacter.FOLD_CASE_EXCLUDE_SPECIAL_I + : UCharacter.FOLD_CASE_DEFAULT); + // start by stripping the trailing whitespace from all the rules // (this is all the whitespace following each semicolon in the // description). This allows us to look for rule-set boundaries @@ -2052,10 +2079,12 @@ private String adjustForContext(String result) { // should only happen when deserializing, etc. capitalizationBrkIter = BreakIterator.getSentenceInstance(locale); } + // Clone the break iterator to avoid mutating it (thread safety). + BreakIterator iter = (BreakIterator) capitalizationBrkIter.clone(); return UCharacter.toTitleCase( locale, result, - capitalizationBrkIter, + iter, UCharacter.TITLECASE_NO_LOWERCASE | UCharacter.TITLECASE_NO_BREAK_ADJUSTMENT); } diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/be.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/be.res index 7dac60071b09..18b6952aa6c7 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/be.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/be.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/bg.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/bg.res index 548557c5dc91..9e99fbd1edbc 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/bg.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/bg.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ca.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ca.res index cf684898d69a..3899fb05a561 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ca.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ca.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/cy.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/cy.res index 5a1547445939..c0722341649b 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/cy.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/cy.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/da.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/da.res index b8d5b4ad8f6c..0c78dd830e67 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/da.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/da.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/de.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/de.res index 3fc539c48acd..fc872c7aeefe 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/de.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/de.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/en.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/en.res index 328d89bec94f..3c7dae4d3c96 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/en.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/en.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/es.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/es.res index 44ff283005fa..faf2cf08c2be 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/es.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/es.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fo.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fo.res index f86ed8e7d171..24b2d0d72e65 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fo.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fo.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr.res index a49f496cfcdd..f5319212ee82 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr_BE.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr_BE.res index 9d0954b5ceef..732b0affad4a 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr_BE.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr_BE.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr_CH.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr_CH.res index a069aff1e7db..6967f5eafd5a 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr_CH.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/fr_CH.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ga.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ga.res index d48f88ea6358..c398d1c1233b 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ga.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ga.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/is.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/is.res index 71bd3878e176..c8cd247260fd 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/is.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/is.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/it.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/it.res index 2347d99e4185..7123f2602d62 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/it.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/it.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/km.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/km.res index 85220441c50b..6e90ee13e9fc 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/km.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/km.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/mk.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/mk.res index f6100b568913..ec82881d5afa 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/mk.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/mk.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/mt.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/mt.res index c2dfacc91fca..f63af89ce2aa 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/mt.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/mt.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/no.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/no.res index ba6ec8832629..81780dcd2e6d 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/no.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/no.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/pt.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/pt.res index 5b06aa3fc03a..cfa6b50a8995 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/pt.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/pt.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/pt_PT.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/pt_PT.res index 35e2aa822117..0d49cf57a77c 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/pt_PT.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/pt_PT.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ru.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ru.res index 7658c578e2ec..8ee25973a20a 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ru.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/ru.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/sr.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/sr.res index 5f85b1cee86a..c1e0d28aeb4f 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/sr.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/sr.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/sv.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/sv.res index 6176d56b823c..fad08d7dd85f 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/sv.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/sv.res differ diff --git a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/uk.res b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/uk.res index 0a846e77ac2d..c27b2004bc52 100644 Binary files a/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/uk.res and b/icu4j/main/core/src/main/resources/com/ibm/icu/impl/data/icudata/rbnf/uk.res differ