Equivalent to * nix fold in PowerShell

Today I had several hundred items (identifiers from a SQL query) and needed to be inserted into another query so that they could be read by an analyst. I need the * nix command fold

. I wanted to take 300 lines and reformat them as multiple numbers per space separated line. I would use fold -w 100 -s

.

Similar tools on * nix include fmt

and par

.

On Windows, is there an easy way to do this in PowerShell? I expected one of the teams to *-Format

do this, but I could not find it. I am using PowerShell v4.

See https://unix.stackexchange.com/questions/25173/how-can-i-wrap-text-at-a-certain-column-size

# Input Data
# simulate a set of 300 numeric IDs from 100,000 to 150,000
100001..100330 | 
    Out-File _sql.txt -Encoding ascii

# I want output like:
# 100001,  100002,  100003,  100004,  100005, ... 100010, 100011
# 100012,  100013,  100014,  100015,  100016, ... 100021, 100021
# each line less than 100 characters.

      

+2


source to share


5 answers


Depending on how big the file you can read it all into memory, concatenate it with spaces and then split by 100 * characters or the next space

(Get-Content C:\Temp\test.txt) -join " " -split '(.{100,}?[ |$])' | Where-Object{$_}

      

This regex searches for 100 characters and then the first place after that. It's a match then -split

, but since the pattern is parenthesized, the match is returned instead of discarded. Where

removes empty records created between matches.

Small sample for proof of theory

@"
134
124
1
225
234
4
34
2
42
342
5
5
2
6
"@.split("`n") -join " "  -split '(.{10,}?[ |$])' | Where-Object{$_}

      

The above is split into 10 characters where possible. If they cannot be saved. The pattern is based on my head banging on the keyboard.



134 124 1 
225 234 4 
34 2 42 
342 5 5 
2 6

      

Then you can turn that into a function to get the simplicity you are most likely looking for. It might get better, but it's not really the focus of the answer.

Function Get-Folded{
    Param(
        [string[]]$Strings,
        [int]$Wrap = 50
    )
    $strings  -join " " -split "(.{$wrap,}?[ |$])" | Where-Object{$_}
}

      

Again with samples

PS C:\Users\mcameron> Get-Folded -Strings (Get-Content C:\temp\test.txt) -wrap 40
"Lorem ipsum dolor sit amet, consectetur 
adipiscing elit, sed do eiusmod tempor incididunt 
ut labore et dolore magna aliqua. Ut enim 
ad minim veniam, quis nostrud exercitation 
... output truncated...

      

You can see that it should be divisible by 40 characters, but the second line is longer. He split into the next space after 40 to preserve the word.

+7


source


If it is one item per line and you want to concatenate all 100 items into one line separated by a space, you can put all the output in a text file, do this:



gc c:\count.txt -readcount 100 | % {$_ -join " "}

      

+1


source


When I saw this, the first thing that crossed my mind was the abuse of Format-Table for this, mainly because it knows how to properly split the lines when you specify the width. After the feature appears, it seems that the other solutions presented are shorter and probably easier to understand, but I figured I would go ahead and post this solution anyway:

function fold {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline)]
        $InputObject,
        [Alias('w')]
        [int] $LineWidth = 100,
        [int] $ElementWidth
    )

    begin {
        $SB = New-Object System.Text.StringBuilder

        if ($ElementWidth) {
            $SBFormatter = "{0,$ElementWidth} "
        }
        else {
            $SBFormatter = "{0} "
        }
    }

    process {
        foreach ($CurrentObject in $InputObject) {
            [void] $SB.AppendFormat($SBFormatter, $CurrentObject)
        }
    }

    end {
        # Format-Table wanted some sort of an object assigned to it, so I 
        # picked the first static object that popped in my head:
        ([guid]::Empty | Format-Table -Property @{N="DoesntMatter"; E={$SB.ToString()}; Width = $LineWidth } -Wrap -HideTableHeaders |
            Out-String).Trim("`r`n")
    }
}

      

Using this parameter gives the result as follows:

PS C:\> 0..99 | Get-Random -Count 100 | fold
1 73 81 47 54 41 17 87 2 55 30 91 19 50 64 70 51 29 49 46 39 20 85 69 74 43 68 82 76 22 12 35 59 92 
13 3 88 6 72 67 96 31 11 26 80 58 16 60 89 62 27 36 37 18 97 90 40 65 42 15 33 24 23 99 0 32 83 14  
21 8 94 48 10 4 84 78 52 28 63 7 34 86 75 71 53 5 45 66 44 57 77 56 38 79 25 93 9 61 98 95          

PS C:\> 0..99 | Get-Random -Count 100 | fold -ElementWidth 2
74 89 10 42 46 99 21 80 81 82  4 60 33 45 25 57 49  9 86 84 83 44  3 77 34 40 75 50  2 18  6 66 13  
64 78 51 27 71 97 48 58  0 65 36 47 19 31 79 55 56 59 15 53 69 85 26 20 73 52 68 35 93 17  5 54 95  
23 92 90 96 24 22 37 91 87  7 38 39 11 41 14 62 12 32 94 29 67 98 76 70 28 30 16  1 61 88 43  8 63  
72                                                                                                  

PS C:\> 0..99 | Get-Random -Count 100 | fold -ElementWidth 2 -w 40
21 78 64 18 42 15 40 99 29 61  4 95 66  
86  0 69 55 30 67 73  5 44 74 20 68 16  
82 58  3 46 24 54 75 14 11 71 17 22 94  
45 53 28 63  8 90 80 51 52 84 93  6 76  
79 70 31 96 60 27 26  7 19 97  1 59  2  
65 43 81  9 48 56 25 62 13 85 47 98 33  
34 12 50 49 38 57 39 37 35 77 89 88 83  
72 92 10 32 23 91 87 36 41              

      

+1


source


Here's what I ended up using.

# simulate a set of 300 SQL IDs from 100,000 to 150,000
100001..100330 | 
    %{ "$_, " } | # I'll need this decoration in the SQL script
    Out-File _sql.txt -Encoding ascii

gc .\_sql.txt -ReadCount 10 | %{ $_ -join ' ' }

      

Thank you all for your efforts and responses. I'm really surprised I couldn't do it with help Format-Table

without using [guid]::Empty

Ron Edward's answer.

My IDs are much more consistent than the example I gave, so using Noah is gc -ReadCount

by far the simplest solution in this particular dataset, but in the future I would probably use Matt's answer or the Emperor related answers in the comments.

+1


source


I came up with this:

$array = 
(@'
1
2
3
10
11
100
101
'@).split("`n") |
foreach {$_.trim()}

$array = $array * 40

$SB = New-Object Text.StringBuilder(100,100)

foreach ($item in $array) {

Try { [void]$SB.Append("$item ") }

Catch {
         $SB.ToString()
         [void]$SB.Clear()
         [Void]$SB.Append("$item ")
      }
}    
#don't forget the last line
$SB.ToString()

1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 
1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 
1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 
1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 
1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 
1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 
1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 1 2 3 10 11 100 101 

      

It may not be as compact as you hoped and there may be better ways to do it, but it seems to work.

0


source







All Articles