You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Need APIs for unicode case mapping and case folding #20674
The Unicode function for determining the category of Unicode characters (System.Globalization.CharUnicodeInfo.GetUnicodeCategory(char)) appears to reflect a fairly recent version of the Unicode standard. However, the functions for performing Unicode case mapping (culture-insensitive uppercase and lowercase) appear to reflect Unicode version 1.0. This mismatch was a severe impediment for implementing spec-compliant case folding in the VB compiler.
There is also no support whatsoever for performing case folding according to the Unicode specification (simplified or otherwise). APIs in the platform to do this would help with any language that, like VB, wants to depend on the Unicode specification for the meaning of case-insensitive identifiers.
This is something I'd like to do. I think the open issue is how we support this on Windows (since I think that we can get Case Folding functionality from ICU).
In general, we've tried to move away from the framework itself shipping globalization data and used the OS provided APIs instead. Since Windows doesn't currently expose a way to do case folding, we'd have to figure out what to do.
We already have a casing APIs on TextInfo and String class. I understand we use the underlying OS for that and this is by design as we need to avoid carrying any globalization data as possible. what exactly the scenario that is not working for you?
The scenario is case folding for the purposes of comparing identifiers in a case insensitive programming language according to the rules described in the Unicode specification. Case mapping is not enough; that is explained in some detail in the Unicode specification. There is no case folding API today.
Considering we didn't get high demand on this functionality and we'll need to carry some Unicode data to be able to support it, I would suggest this functionality can be implemented in some NuGet package and doesn't have to be in the core for now. If we see there is more demand on that we can consider having it in core. we can use corefxlab if needed for hosting the code if needed.
In PowerShell/PowerShell#8120 I provide a plan. In short we hope to get performance benefits in PowerShell, RegEx and string comparisons in general.
In PowerShell we could win in engine because it use string comparisons everywhere. Also we could speed up Select-String cmdlet get parity with Unix grep and fastest Rust ripgrep utility. Ripgrep uses simple case folding. It show that we could get great win in CoreFX RegEx too.
On the week I prepared alfa code for simple case folding and while the results are encouraging.
If we did want to provide APIs for this, they'd probably look like the following:
publicnamespaceSystem.Globalization
{publicstaticclassCharUnicodeInfo{// performs "simple" culture-unaware mapping to uppercase using CharUnicodeInfo backing datapublicstaticcharToUpperInvariant(charch);publicstaticintToUpperInvariant(intcodePoint);publicstaticRuneToUpperInvariant(Runerune);// performs "simple" culture-unaware mapping to lowercase using CharUnicodeInfo backing datapublicstaticcharToLowerInvariant(charch);publicstaticintToLowerInvariant(intcodePoint);publicstaticRuneToLowerInvariant(Runerune);// performs "simple" culture-unaware mapping to titlecase using CharUnicodeInfo backing datapublicstaticcharToTitleInvariant(charch);publicstaticintToTitleInvariant(intcodePoint);publicstaticRuneToTitleInvariant(Runerune);// performs "simple" case-fold mapping using CharUnicodeInfo backing datapublicstaticcharToCaseFold(charch);publicstaticintToCaseFold(intcodePoint);publicstaticRuneToCaseFold(Runerune);}}
The behavior of all of these APIs is that they'd use the data that's already present in the code-behind for CharUnicodeInfo (generated from UnicodeData.txt and CaseFolding.txt). APIs which take int will throw if the input is outside the range [ U+0000..U+10FFFF ] (UTF-16 surrogate code points are allowed and will map to themselves). APIs which take char and Rune do not throw.
@tarekgh If we did https://github.com/dotnet/corefx/issues/41333, I think that would make sense. Otherwise we could end up with a mixture of ICU and NLS behaviors hanging off of string and char, and IMO it would be difficult to reason about.
The behavior of all of these APIs is that they'd use the data that's already present in the code-behind for CharUnicodeInfo (generated from UnicodeData.txt and CaseFolding.txt).
I don't understand. Unicode has no concept of an invariant mapping (i.e. one that that fails to follow the evolving Unicode standard).
If we were to follow these patterns, then we'd probably end up with this behavior:
If you call the CharUnicodeInfo APIs, we use our carried data (currently Unicode 12.1, but likely Unicode 13.0 by the time the implementation ships).
If you call any other API, the following logic occurs:
If GlobalizationMode.Invariant is set, we fold only ASCII and leave everything else as-is, regardless of OS. Otherwise:
If we're on a version of Win10 where OS natively carries the ICU data, or if we're on a non-Windows OS, we p/invoke into ICU to perform case folding on our behalf.
If we're on a version of Windows where the OS doesn't natively carry the ICU data, we fall back to the CharUnicodeInfo tables.
This follows the general concept of CharUnicodeInfo being a fully self-contained data set, while string, char, and Rune all fall back to TextInfo, which interfaces with our unmanaged dependencies.
Personally I think it's a little confusing to have multiple APIs that all share the same name but do slightly different things, but it does follow established convention.
Thanks, @GrabYourPitchforks for your proposal. I talked with you offline, I just want to mention what is the idea I like to have. Moving the CaseFolding Library from corefxlab to runtime libraries repo but not including it as part of the shipping SDK and instead, we ship it as a separate independent NuGet package so anyone wants to get the case-folding feature will just need to depend on this package. The reason is we are going to carry the case folding Unicode tables which will increase the footprint size of the product if we ship it inside the SDK. So only apps/libraries need to use this feature will need to carry it.
Here are some comments if we go with this plan:
Properly we'll need to rename the package to something more generic so we can accommodate more features as needed. I would prefer something Microsoft.Extensions.Globalization.
Your proposed APIs look good we'll have to convert the proposal to be extension methods instead.
We shouldn't have any method on TextInfo for case-folding.
We need to visit the current APIs in the package to look if we need to keep it or polish it.
Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.
This issue will now be closed since it had been marked no-recent-activity but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.
Activity
iSazonov commentedon Oct 31, 2018
Could we start designing the simple case folding API?
tarekgh commentedon Oct 31, 2018
@iSazonov wouldn't the supported string normalization and casing APIs are not enough in your case?
gafter commentedon Oct 31, 2018
@tarekgh What APIs are you suggesting approximate case folding?
tarekgh commentedon Oct 31, 2018
We already have a casing APIs on TextInfo and String class. I understand we use the underlying OS for that and this is by design as we need to avoid carrying any globalization data as possible. what exactly the scenario that is not working for you?
gafter commentedon Oct 31, 2018
The scenario is Case Folding as specified in the Unicode specification. See also
tarekgh commentedon Oct 31, 2018
I know that, I am asking about what is your scenario you need the case folding and case mapping is not enough?
gafter commentedon Oct 31, 2018
The scenario is case folding for the purposes of comparing identifiers in a case insensitive programming language according to the rules described in the Unicode specification. Case mapping is not enough; that is explained in some detail in the Unicode specification. There is no case folding API today.
tarekgh commentedon Nov 1, 2018
Thanks @gafter
Considering we didn't get high demand on this functionality and we'll need to carry some Unicode data to be able to support it, I would suggest this functionality can be implemented in some NuGet package and doesn't have to be in the core for now. If we see there is more demand on that we can consider having it in core. we can use corefxlab if needed for hosting the code if needed.
iSazonov commentedon Nov 1, 2018
Please see https://github.com/dotnet/corefx/issues/33047 and PowerShell/PowerShell#8120
In PowerShell/PowerShell#8120 I provide a plan. In short we hope to get performance benefits in PowerShell, RegEx and string comparisons in general.
In PowerShell we could win in engine because it use string comparisons everywhere. Also we could speed up Select-String cmdlet get parity with Unix grep and fastest Rust ripgrep utility. Ripgrep uses simple case folding. It show that we could get great win in CoreFX RegEx too.
On the week I prepared alfa code for simple case folding and while the results are encouraging.
GrabYourPitchforks commentedon Sep 27, 2019
See also https://github.com/dotnet/corefx/issues/41333, which is a proposal to make
string/char/Runeuse these mappings by default. It doesn't involve any new API addition.GrabYourPitchforks commentedon Sep 27, 2019
If we did want to provide APIs for this, they'd probably look like the following:
The behavior of all of these APIs is that they'd use the data that's already present in the code-behind for
CharUnicodeInfo(generated from UnicodeData.txt and CaseFolding.txt). APIs which takeintwill throw if the input is outside the range[ U+0000..U+10FFFF ](UTF-16 surrogate code points are allowed and will map to themselves). APIs which takecharandRunedo not throw.tarekgh commentedon Sep 27, 2019
@GrabYourPitchforks would it make sense to move these functionality to char and string classes (and support string case folding too)?
GrabYourPitchforks commentedon Sep 27, 2019
@tarekgh If we did https://github.com/dotnet/corefx/issues/41333, I think that would make sense. Otherwise we could end up with a mixture of ICU and NLS behaviors hanging off of
stringandchar, and IMO it would be difficult to reason about.tarekgh commentedon Sep 28, 2019
I believe in the near future we'll use ICU across all platforms which will help not having this mixture issue.
gafter commentedon Sep 30, 2019
I don't understand. Unicode has no concept of an invariant mapping (i.e. one that that fails to follow the evolving Unicode standard).
5 remaining items
GrabYourPitchforks commentedon Feb 12, 2020
@tarekgh As a straw man, here's what it might look like to spread these APIs out on the classes where they naturally belong:
If we were to follow these patterns, then we'd probably end up with this behavior:
CharUnicodeInfoAPIs, we use our carried data (currently Unicode 12.1, but likely Unicode 13.0 by the time the implementation ships).GlobalizationMode.Invariantis set, we fold only ASCII and leave everything else as-is, regardless of OS. Otherwise:CharUnicodeInfotables.This follows the general concept of
CharUnicodeInfobeing a fully self-contained data set, whilestring,char, andRuneall fall back toTextInfo, which interfaces with our unmanaged dependencies.Personally I think it's a little confusing to have multiple APIs that all share the same name but do slightly different things, but it does follow established convention.
Thoughts?
tarekgh commentedon Feb 12, 2020
Thanks, @GrabYourPitchforks for your proposal. I talked with you offline, I just want to mention what is the idea I like to have. Moving the CaseFolding Library from corefxlab to runtime libraries repo but not including it as part of the shipping SDK and instead, we ship it as a separate independent NuGet package so anyone wants to get the case-folding feature will just need to depend on this package. The reason is we are going to carry the case folding Unicode tables which will increase the footprint size of the product if we ship it inside the SDK. So only apps/libraries need to use this feature will need to carry it.
Here are some comments if we go with this plan:
Thanks for your thoughts on this issue.
dotnet-policy-service commentedon Dec 17, 2024
Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.
This process is part of our issue cleanup automation.
dotnet-policy-service commentedon Dec 31, 2024
This issue will now be closed since it had been marked
no-recent-activitybut received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.