# Powershell, <s>123</s> 115 bytes <!-- language-all: lang-powershell --> switch -r($args|% t*y){'\s'{$a=0}'\S'{$w+=!$a;$a=1}'(?s).'{$b++}' '{$l++}}$c="$b".Length "{0,$c} {1,$c} $b"-f$l,+$w Test script: $f = { switch -r($args|% t*y){ # evaluate all matched cases '\s' {$a=0} # any whitespace (newline not included) '\S' {$w+=!$a;$a=1} # any not-whitespace (newline not included) '(?s).'{$b++} # any char (newline included!) '`n' {$l++} # new line char } $c="$b".Length "{0,$c} {1,$c} $b"-f$l,+$w } @( , ("a b c d`n", "1 4 8") , ("a b c d e f`n", " 1 6 12") , (" a b c d e f `n", " 1 6 16") , ("a`nb`nc`nd`n", "4 4 8") , ("a`n`n`nb`nc`nd`n", " 6 4 10") , ("abc123{}[]()...`n", " 1 1 16") , ("`n", "1 0 1") , (" `n", "1 0 4") , ("`n`n`n`n`n", "5 0 5") , ("`n`n`na`nb`n", "5 2 7") ) | % { $s,$e = $_ $r = &$f $s "$($e-eq$r): $r" } Output: True: 1 4 8 True: 1 6 12 True: 1 6 16 True: 4 4 8 True: 6 4 10 True: 1 1 16 True: 1 0 1 True: 1 0 4 True: 5 0 5 True: 5 2 7 Explanation: * `$args|% t*y` splits arument strings into chars * `switch -r($args|% t*y)` evaluate *all matched cases* * `'\s'` case for any whitespace * `'\S'` case for any non-whitespace * `'(?s).'` case for any char (newline included) * `'\n'` case for newline char (newline represent itself) * `$c="$b".Length` calculate a length of bytes number. $b is always max($l,$w,$b) by design * `"{0,$c} {1,$c} $b"-f$l,+$w` format numbers with same length. The variable $w converts to int. It need for strings without words. Other variables formats 'as is' because 'The input will always contain a trailing newline' and $l and $b cannot be 0.