Skip to content

Formatting system: format large numbers with thousands separators (digit grouping) by default #13590

@mklement0

Description

@mklement0

Summary of the new feature/enhancement

The output formatting system's purpose is to present data to the human reader.
(As such - because the formatted output isn't meant for programmatic processing - it isn't part of PowerShell's breaking-changes contract.)

Currently, large numbers are output without thousands separators, i.e. without grouping the digits for easier comprehension.

I suggest applying this grouping to all numbers (that aren't explicitly formatted via formatting data):

# WISHFUL THINKING - but you can get a preview with the prototype below.

# Number by itself (out-of-band formatting)
PS> 1000
1,000

# Implicit in-band formatting (table or list)
PS> @{ num = 1000 }

Name                           Value
----                           -----
num                            1,000

# Should also automatically apply to types with explicit formatting data 
# (unless number formatting is part of a given list item / table column).
# Note the "Size" column.
PS> Get-Item $PROFILE

    Directory: /Users/jdoe/.config/powershell

UnixMode   User             Group                 LastWriteTime           Size  Name
--------   ----             -----                 -------------           ----  ----
-rw-r--r-- jdoe             staff              10/23/2019 22:31           1,934  Microsoft.PowerShell_profile.ps1

As @ThomasNieto proposes below, a new preference variable and new switch for the Format-* cmdlets could allow opting into the old behavior. E.g.: $PSThousandsGrouping with values $true and $false (default $true), and switch
-ThousandsGrouping.

Proposed technical implementation details (optional)

Here's a quick prototype that uses the ETS. It is not the suggested implementation, for reasons of both performance and also changing the behavior of explicit .ToString() calls.

A proper implementation would require modifying the formatting system itself.

# Prototype:
[int16], [int], [long], [double], [decimal], [bigint], [uint16], [uint], [uint64] | % {

  Update-TypeData -TypeName $_.FullName  -MemberType ScriptMethod -MemberName ToString -Value { 
    # Determine how many decimal places there are in the original representation.
    # Note: PowerShell's string interpolation uses the *invariant* culture, so '.'
    #       can reliably be assumed to be the decimal mark.
    $numDecimalPlaces = ("$this" -replace '^[^.]+(?:.(.+))?', '$1').Length

    # Format with thousands grouping and the same number of decimal places.
    # Note: This will create a culture-sensitive representation
    #       just like with the default output formatting.
     # CAVEAT:
     #  To avoid a crash (from infinite recursion?), both .psobject.BaseObject 
     #  and the -f operator must be used.
     #  ($this.psobject.BaseObject.ToString("...") also crashes).
    "{0:N$numDecimalPlaces}" -f $this.psobject.BaseObject
  } -Force

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Enhancementthe issue is more of a feature request than a bugResolution-No ActivityIssue has had no activity for 6 months or moreWG-Enginecore PowerShell engine, interpreter, and runtime

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions