Skip to content

Instantly share code, notes, and snippets.

@togakangaroo
Created May 31, 2015 13:42
Show Gist options
  • Save togakangaroo/4454e2aa839ea947720e to your computer and use it in GitHub Desktop.
Save togakangaroo/4454e2aa839ea947720e to your computer and use it in GitHub Desktop.
Powershell script to parse an estimation file in an (indent, estimate, text[, description]) format in a csv-able structure
param(
[Parameter(Mandatory=$true)]$File
)
$lines = foreach($ln in Get-Content $File) {
if($ln -match '^(\t*)(.+)$') {
@{
originalText = $ln
text = $Matches[2]
indentLevel = $Matches[1].Length
}
}
}
$lines = $lines | ? { $_.text -and $_.text.Trim() }
function create-Indents($count) {
return ([System.Linq.Enumerable]::Range(0, $count) | % { " " }) -join ''
}
function parse-Tree($currentLine, $lines) {
function writein($text) {
# Write-Host "$(create-Indents $currentLine.indentLevel)$text" -ForegroundColor Cyan
}
writein $currentLine.text
writein "- $($lines.Count) remaining"
$nextLine, $otherLines = $lines
if(-not $currentLine) {
return @{
nodes = @()
remaining = @()
}
}
$node = @{
line = $currentLine
indentLevel = $currentLine.indentLevel
text = $currentLine.text
}
if(-not $nextLine -or $nextLine.indentLevel -lt $currentLine.indentLevel) {
$node.children = @()
writein "- done"
return @{
nodes = @($node)
remaining = $lines
}
}
if($nextLine.indentLevel -eq $currentLine.indentLevel) {
writein "- going over"
$siblingsTree = parse-Tree $nextLine $otherLines
writein "- adding $($siblingsTree.nodes.Count) siblings to $($node.text)"
return @{
nodes = @($node) + $siblingsTree.nodes
remaining = $siblingsTree.remaining
}
}
if($nextLine.indentLevel -gt $currentLine.indentLevel) {
writein "- going down"
$nextTree = parse-Tree $nextLine $otherLines
writein "- adding $($nextTree.nodes.Count) children to $($node.text)"
$node.children = $nextTree.nodes
#todo - this can be slicker as it basically just repeats the above
$nextLine, $otherLines = $nextTree.remaining
if($nextLine.indentLevel -eq $currentLine.indentLevel){
writein "- going over"
$siblingsTree = parse-Tree $nextLine $otherLines
writein "- adding $($siblingsTree.nodes.Count) siblings to $($node.text)"
return @{
nodes = @($node) + $siblingsTree.nodes
remaining = $siblingsTree.remaining
}
}
if(-not $nextLine -or $nextLine.indentLevel -lt $currentLine.indentLevel) {
writein "- done"
return @{
nodes = @($node)
remaining = @($nextLine) + $otherLines
}
}
}
}
function visitLast($node, [scriptblock]$fn) {
if(-not $node) {
return
}
foreach($child in $node.children){
visitLast $child $fn
}
&$fn $node
}
function visitFirst($node, [scriptblock]$fn, $acc) {
if(-not $node) {
return
}
&$fn $node $acc
foreach($child in $node.children){
visitFirst $child $fn $acc
}
}
$head, $tail = $lines
$parsed = parse-Tree $head $tail
function parse-nodeText($node) {
$parts = @( $node.text -split ',' | % { $_.Trim() } )
if($parts[0] -match '^(\d+)\s*(-\s*(\d+))?') {
$node.item = $parts[1]
$node.description = $parts[2]
if($node.children) {
Write-Warning "Line has an estimate and children - ignoring children sum. '$($node.line.text)'"
}
$node.estimate = [int]$matches[1],[int]$matches[1]
if($matches.Count -eq 4) {
$node.estimate[1] = [int]$matches[3]
}
} else {
$node.item = $parts[0]
$node.description = $parts[1]
$node.estimate = $null,$null
if(-not $node.children) {
Write-Warning "no estimate on leaf '$($node.text)'"
}
foreach($child in $node.children) {
$node.estimate[0] += $child.estimate[0]
$node.estimate[1] += $child.estimate[1]
}
}
}
foreach($node in $parsed.nodes) {
visitLast $node ${function:parse-nodeText}
}
function create-OutputItem($node, $acc) {
$hash = [ordered]@{
min = $node.estimate[0]
max = $node.estimate[1]
item = "$(create-Indents $node.indentLevel)$($node.item)"
description = $node.description
}
$acc.Add( (New-Object PsObject -property $hash) ) | out-null
}
$outgoingItems = new-object System.Collections.ArrayList
foreach($node in $parsed.nodes) {
visitFirst $node ${function:create-OutputItem} $outgoingItems
}
return $outgoingItems
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment