KEMBAR78
Add support for thousands separators in [bigint] casting by AbishekPonmudi · Pull Request #25396 · PowerShell/PowerShell · GitHub
Skip to content

Conversation

@AbishekPonmudi
Copy link
Contributor

@AbishekPonmudi AbishekPonmudi commented Apr 21, 2025

PR Summary

This PR resolves a parsing issue in PowerShell where numeric strings containing thousands separators (e.g., 1,000) fail to convert into [bigint], resulting in an InvalidArgument exception. The root cause is the absence of NumberStyles.AllowThousands and lack of formatting cleanup before conversion. This update ensures consistent and locale-aware conversion behavior for large numeric strings.

PR Context

The issue occurs when users attempt to cast strings like '1,000' to [bigint], and PowerShell does not account for grouping symbols defined by culture. This leads to type conversion errors in scripts or user input relying on formatted numbers.

Solution

Updates made to the ConvertFrom() method in LanguagePrimitives.cs include:

  • Casting sourceValue using (string) instead of as string for type safety.
  • Dynamically handling culture-specific formatting to ensure group separators are correctly removed.
  • Including NumberStyles.AllowThousands for accurate parsing of BigInteger.

Error Message Before Fix

InvalidArgument: Cannot convert value "1,000" to type "System.Numerics.BigInteger". Error: "The value could not be parsed."

After Fix

PS> [bigint] '1,000'
'1000'

Why This Fix?

  • Prevents casting errors when handling numeric strings with thousands separators.
  • Improves PowerShell’s type conversion reliability.
  • Ensures compatibility with standard numeric formatting.

PR Checklist

Related Issues

FIXED ----

AbishekPonmudi added a commit to AbishekPonmudi/PowerShell that referenced this pull request Apr 22, 2025
…casting errors (PowerShell#25396)

# Issue Summary
PowerShell fails to convert numeric strings with thousands separators (e.g., commas) to `[bigint]`, causing casting errors. This occurs because the `ConvertFrom()` method in `LanguagePrimitives.cs` doesn’t handle formatted numbers.

## Cause
- The `ConvertTo()` method doesn’t remove thousands separators (e.g., `,` in en-US), leading to `BigInteger.Parse()` failures.
- This affects scripts handling large numbers with separators.

## Solution
Modify `ConvertFrom()` to:
- Detect the culture-specific thousands separator.
- Remove it before conversion.
@AbishekPonmudi AbishekPonmudi requested a review from iSazonov April 22, 2025 07:01
@iSazonov
Copy link
Collaborator

In related issue there is a reference to code where exception is raised

if (resultType == typeof(BigInteger))
{
// Fallback for BigInteger: manual parsing using any common format.
NumberStyles style = NumberStyles.AllowLeadingSign
| NumberStyles.AllowDecimalPoint
| NumberStyles.AllowExponent
| NumberStyles.AllowHexSpecifier;
return BigInteger.Parse(strToConvert, style, NumberFormatInfo.InvariantInfo);
}

I guess it is right place for a fix.
Also I don't think we should do any normalizations since BigInteger.(Try)Parser() can do all work.

@AbishekPonmudi
Copy link
Contributor Author

Hey @iSazonov,

Thanks for the heads-up! I went ahead and tweaked LanguagePrimitives.cs (lines 2957–2966) to fix that BigInteger.Parse() issue with thousands separators. I ditched NumberStyles.AllowHexSpecifier, swapped BigInteger.Parse() for BigInteger.TryParse() to keep things smooth, and made sure it handles stuff like "1,000" → 1000 and "5,432,100" → 5432100 correctly.

if (resultType == typeof(BigInteger)) 
{ 
    // Adjust NumberStyles to remove AllowHexSpecifier for standard numeric parsing
    NumberStyles style = NumberStyles.AllowLeadingSign 
        | NumberStyles.AllowDecimalPoint 
        | NumberStyles.AllowExponent; // Removed AllowHexSpecifier  

    BigInteger parsedValue;
    if (BigInteger.TryParse(strToConvert, style, NumberFormatInfo.InvariantInfo, out parsedValue))
    {
        return parsedValue;
    }
    throw new PSInvalidCastException("Failed to convert string to BigInteger.");
}

Copy link
Contributor Author

@AbishekPonmudi AbishekPonmudi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review, @iSazonov! I’ve updated LanguagePrimitives.cs to remove the unnecessary comment, replaced BigInteger.TryParse() with BigInteger.Parse(), and adjusted NumberStyles to allow thousands separators. Let me know if any further refinements are needed!

@iSazonov
Copy link
Collaborator

@AbishekPonmudi Please add new tests to cover the code. (The tests should use current culture NumberGroupSeparator .)

Copy link
Contributor Author

@AbishekPonmudi AbishekPonmudi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review, @iSazonov! I’ve updated the code to remove manual separator normalization and now rely on BigInteger.Parse() with NumberStyles.AllowThousands to handle formatted numeric strings directly. Let me know if any further refinements are needed!

@iSazonov
Copy link
Collaborator

@AbishekPonmudi Please add tests to cover all scenarios you are trying to fix.

@AbishekPonmudi
Copy link
Contributor Author

AbishekPonmudi commented Apr 26, 2025

@AbishekPonmudi Please add tests to cover all scenarios you are trying to fix.

I ran manual tests for different locales using the file BigIntegerCultureHandling.ps1 as mentioned in the visual reference. I verified that PowerShell correctly handles thousands of separators, everything seems to be working fine based on these tests.
Please let me know if there are any issues or if any further refinements are needed :)

@iSazonov
Copy link
Collaborator

@AbishekPonmudi You should add tests to the PR.

AbishekPonmudi added a commit to AbishekPonmudi/PowerShell that referenced this pull request Apr 27, 2025
AbishekPonmudi added a commit to AbishekPonmudi/PowerShell that referenced this pull request Apr 27, 2025
@AbishekPonmudi
Copy link
Contributor Author

Hi @iSazonov,

I have submitted a separate Pull Request (#25463) that includes the necessary unit tests for BigInteger parsing across different cultures. These tests verify correct handling of thousands separators using PowerShell’s current culture settings.

Please refer to the test PR here: Tests for BigInteger parsing across cultures (#25463).

Let me know if any changes or refinements are needed to do better with the expected behavior....

@iSazonov
Copy link
Collaborator

@AbishekPonmudi If the PR fix #25368 we need tests in the PR which cover scenarios from that issue.

AbishekPonmudi added a commit to AbishekPonmudi/PowerShell that referenced this pull request Apr 28, 2025
@AbishekPonmudi AbishekPonmudi requested a review from mklement0 May 7, 2025 19:29
Describe 'PowerShell Type Conversion - BigInteger Parsing' -Tag 'CI' {

It 'Can convert formatted numbers using PowerShell type system' {
[System.Globalization.CultureInfo]::CurrentCulture = [System.Globalization.CultureInfo]::GetCultureInfo("en-US")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the culture angle is now covered by the de-DE test, I suggest removing this.

$convertedValue | Should -Be 1000
}

It 'Handles large comma-separated numbers that previously failed' {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quibble: perhaps better: `Handles large numbers with thousands separators that previously failed'

$convertedValue | Should -Be 1000000
}

It 'Parses number using de-DE culture but falls back to invariant behavior' {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quibble: Since the current culture never comes into play, I wouldn't say "Parses number using de-DE". Perhaps better: Parses a number string using the invariant culture, irrespective of the current culture

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback @mklement0 , I have removed the line as suggested, and updated the "Handles large comma-separated numbers" test to "Handles large numbers with thousands separators" for clarity. Also, I have reworded the "de-DE" test to better reflect that it uses invariant culture, irrespective of the current culture.

Get me again ! if anything needed to better :)

@AbishekPonmudi AbishekPonmudi requested a review from mklement0 May 7, 2025 19:50
Copy link
Contributor

@mklement0 mklement0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iSazonov, everything LGTM now.

@AbishekPonmudi AbishekPonmudi requested a review from iSazonov May 7, 2025 19:55
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

Describe 'PowerShell Type Conversion - BigInteger Parsing' -Tag 'CI' {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please all tests in LanguagePrimitive.Tests.ps1

@AbishekPonmudi AbishekPonmudi requested a review from iSazonov May 8, 2025 07:40
Comment on lines 189 to 194
It 'Can convert formatted numbers using PowerShell type system' {
[System.Globalization.CultureInfo]::CurrentCulture = [System.Globalization.CultureInfo]::GetCultureInfo("en-US")
$formattedNumber = "1,000"
$convertedValue = [System.Management.Automation.LanguagePrimitives]::ConvertTo($formattedNumber, [bigint])
$convertedValue | Should -Be 1000
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test was removed before.

@AbishekPonmudi AbishekPonmudi requested a review from iSazonov May 8, 2025 09:53
@AbishekPonmudi
Copy link
Contributor Author

@iSazonov Is everything is resolved.

@iSazonov

This comment was marked as outdated.

@azure-pipelines

This comment was marked as outdated.

@PowerShell PowerShell deleted a comment from azure-pipelines bot May 8, 2025
@iSazonov iSazonov merged commit 1b786d2 into PowerShell:master May 8, 2025
36 checks passed
@microsoft-github-policy-service
Copy link
Contributor

microsoft-github-policy-service bot commented May 8, 2025

📣 Hey @@AbishekPonmudi, how did we do? We would love to hear your feedback with the link below! 🗣️

🔗 https://aka.ms/PSRepoFeedback

@iSazonov
Copy link
Collaborator

iSazonov commented May 8, 2025

@AbishekPonmudi Thanks for your contribution! Please update the PR description to exactly reflect the change.

@iSazonov
Copy link
Collaborator

iSazonov commented May 8, 2025

@mklement0 Thanks for review!

@AbishekPonmudi
Copy link
Contributor Author

AbishekPonmudi commented May 8, 2025

@iSazonov Thank you for reviewing my contribution! I appreciate your feedback. I have updated the PR description to reflect the implemented changes.

@AbishekPonmudi AbishekPonmudi deleted the patch-3 branch May 9, 2025 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bigint] casting breaks with strings containing thousands separators (commas)

3 participants