views:

93

answers:

3

Background

Python has "textwrap" and "dedent" functions. They do pretty much what you expect to any string you supply.

textwrap.wrap(text[, width[, ...]])

Wraps the single paragraph in text (a string) so every line is at most width characters long. Returns a list of output lines, without final newlines.

textwrap.dedent(text)

Remove any common leading whitespace from every line in text.

http://docs.python.org/library/textwrap.html

Question:

How do you do this in Windows PowerShell, (or with .NET methods you call from PowerShell)?

+1  A: 

I think you should create a CLI utility with this behaviour and customize it as you like. And then just use it as a command in your shell. Maybe you will also need to add you script into PATH.

L1ker
+3  A: 

This is a negligent code...

#requires -version 2.0
    function wrap( [string]$text, [int]$width ) {
    $i=0;
    $text.ToCharArray() | group { [Math]::Floor($i/$width); (gv i).Value++ } | % { -join $_.Group }
}

function dedent( [string[]]$text ) {
    $i = $text | % { $_ -match "^(\s*)" | Out-Null ; $Matches[1].Length } | sort | select -First 1
    $text -replace "^\s{$i}"
}
A: 

Looking at the results in python at http://try-python.mired.org/, it appears that the correct algorithm splits at word boundaries, rather than taking fixed-length substrings from the text.

function wrap( [string]$text, [int]$width = 70 ) {
  $line = ''

  # Split the text into words.
  $text.Split( ' '.ToCharArray( ) ) | % {
    # Initialize the first line with the first word.
    if( -not $line ) { $line = $_ }
    else {
      # For each new word, try to add it to the current line.
      $next = $line + ' ' + $_

      # If the new word goes over the limit,
      #  return the last line and start a new one.
      if( $next.Length -ge $width ) { $line; $line = $_ }
      # Otherwise, use the updated line with the new word.
      else { $line = $next }
    }
  }

  # Return the last line, containing the remainder of the text.
  $line
}

And here's an alternate implementation for dedent as well.

function dedent( [string[]]$lines ) {
  # Find the shortest length of leading whitespace common to all lines.
  $commonLength = (
    $lines | % {
      $i = 0
      while( $i -lt $_.Length -and [char]::IsWhitespace( $_, $i ) ) { ++$i }
      $i
    } | Measure-Object -minimum
  ).Minimum

  # Remove the common whitespace from each string
  $lines | % { $_.Substring( $commonLength ) }
}

Hopefully their greater verbosity will provide better clarity :)

Emperor XLII