Find columns where all characters are the same

APL, 25 characters

∩/{0=⍴⍵:⍬⋄(⊂⍵,⍨¨⍳⍴⍵),∇⍞}⍞

I used Dyalog APL (version 13) as my interpreter. It handles both inputs of unequal length and Unicode (UTF-8) characters.

Examples:

      ∩/{0=⍴⍵:⍬⋄(⊂⍵,⍨¨⍳⍴⍵),∇⍞}⍞
abcdefg
avcddeg
acbdeeg

  1 a  4 d  7 g  

      ∩/{0=⍴⍵:⍬⋄(⊂⍵,⍨¨⍳⍴⍵),∇⍞}⍞
test日本
blat日本国foo

  4 t  5 日  6 本 

Explanation, somewhat from right to left:

  • The main chunk of this answer is the direct function (basically, anonymous function), defined within the curly braces. Its right argument is specified by .
    • 0=⍴⍵:⍬ is our first expression, and it checks if we've gotten an empty line (i.e., we are done). It uses a guard (a familiar construct to many functional programmers) to conditionally execute the expression to the right of the colon. In this case, if 0 is equal to the shape/length () of the right argument, we return the empty set ().
    • separates the two expressions within the function. If the previous expression didn't get evaluated (and thus didn't return anything), we move to the next expression.
    • We recursively call the function using the self-reference function (). The argument to the function is a line of non-evaluated user input, given by quote-quad ().
    • ⊂⍵,⍨¨⍳⍴⍵ creates pairs for each character in the string, where each pair's first element is its position in the string, and its second element is the character.
    • ⍳⍴⍵ gives a vector from 1 to ⍴⍵, or the length of the input string.
    • ⍵,⍨¨ applies the commuted concatenation function (,⍨) to each (¨) element to its left (, in this case the user's input) and right. Commuting the concatenation function causes its left and right arguments to be swapped.
    • Finally, we enclose the result using , so that we can differentiate between lines of input.
  • We initially feed our function with user input ().
  • Finally, we reduce (/) our resulting vector of vectors of pairs using the intersection function (), yielding the pairs that are found in all of the sub-vectors.

Golfscript (28 chars)

n/zip:^,,{.^=.&.,1>{;;}*}%n*

There are character set issues when piping Unicode through, so no quarter-point bonus.


J, 57 51 44 40 characters

,.&.>y;y{{.z[y=.I.*/2=/\]z=.];._2]1!:1]3

I'm getting there slowly but surely. This is still far from ideal though I think.

I felt sure that using a hook would be the answer but unfortunately not (44 chars):

,.&.>((];({{.)~)([:I.[:*/2=/\]))];._2]1!:1]3

I may need a completely different method to get any shorter.