Crossword grid verification
Ruby - 215 207

t,*d=$&lt;.map &amp;:chop;n,d,e=t.size+1,(d*S=?#).gsub(/[^#]/,W=" "),-&gt;c,i{puts [c,i/n+1,i%n+1]*" ";exit 1}
0.upto(d.size-1){|i|d[i]==d[-i-1]||e[?R,i];d[i]==W&amp;&amp;(d[i-1]!=W&amp;&amp;d[i+1]!=W||d[i-n]!=W&amp;&amp;d[i+n]!=W)&amp;&amp;e[?L,i]}


Ungolfed:

h, *g = $&lt;.map &amp;:chop
w = h.size+1
g = (g*?#).gsub(/[^#]/," ")
error = -&gt;c,i{ puts [c,i/w+1,i% w+1]*" "; exit 1 }
0.upto(size-1) { |i|
        error[?R, i] if g[i] != g[-i-1]
        error[?L,i] if g[i]==" " &amp;&amp; (g[i-1]!=" " &amp;&amp; g[i+1]!=" " || g[i-w]!=" " &amp;&amp; g[i+w] != " ")
}


.

h, *g = $&lt;.map &amp;:chop


This basically removes the last char (line break) of each input line by calling the chop method on them, and returning an array of the results.

h takes the first element of this array and *g takes the rest. So we end up with the first line in h and the crossword grid lines in g.

g = (g*?#).gsub(/[^#]/," ")


g*?# joins (*) the array g with the "#" (?# is a character literal). This is the same as g.*("#"), or g.join("#"). Then every non # is replaced by a space.

For the symmetry check we just have to check if the char at every index is equals to the char at the opposite index in the string:

0.upto(g.size-1) { |i| if g[i] != g[g.size - i - 1]; error() }


In Ruby we can index strings from the end using negative indexes (starting from -1 instead of 0), so that g[-i-1] is the opposite of g[i] in the string. This saves a few chars:

0.upto(g.size-1) { |i| if g[i] != g[-i-1]; error() }


We can save a ; by using a conditional statement:

0.upto(g.size-1) { |i| error() if g[i] != g[-i-1] }


In the golfed version we can save a few more chars:

0.upto(g.size-1){|i|g[i]==g[-i-1]||error()}


In a previous version I used recursion for iterating over the string:

(f=-&gt;i{g[i]&amp;&amp;f[i+1]&amp;&amp;g[i]!=g[-i-1]&amp;&amp;error()})[0]


An out of bound access to g returns nil, so once g[i] returns nil, this stops the iteration.

Output format:

{ L | R } line-number column-number


L for length errors, and R for rotation error (so L 1 2 means length error at line 1, column 2)