Detect ASCII-art windows made of M and S characters

Retina, 68 67 bytes

Byte count assumes ISO 8859-1 encoding.

S
M
^(M((M)*M)\2)((?<-9>¶M((?<9-3> )*(?(3)!)M|\5)\5)*(?(9)!)¶\1)\4$

Try it online!


Grime, 39 38 bytes

Thanks to Zgarb for saving 1 byte.

e`BB/BB/W+ W/+
B=W|B/W\ * W/\ /*
W=[MS

Try it online!

I'm not sure whether there's a simpler way to enforce the square aspect ratio of the individual window components than using a recursive nonterminal, but this seems to be working quite well.

Explanation

It's best to read the program from the bottom up.

W=[MS

This simply defines a nonterminal (which you can think of as a subroutine that matches a rectangle) W which matches either an M or an S (there's an implicit ] at the end of the line).

B=W|B/W\ * W/\ /*

This defines a non-terminal B which matches about a quarter of the output, i.e. one window panel with the left and top border. Something like this:

MSM
S  
M  

To ensure that this window panel is square, we define B recursively. It's either a window character W, or it's B/W\ * W/\ /* which adds one layer to the right and to the bottom. To see how it does this, let's remove some syntactic sugar:

(B/W[ ]*)(W/[ ]/*)

This is the same, because horizontal concatenation can be written either AB or A B, but the latter has lower precedence than the vertical concatenation / while for the former has higher. So B/W[ ]* is a B with a window character and a row of spaces below. And then we horizontally append W/[ ]/* which is a window character with a column of spaces.

Finally, we assemble these nonterminals into the final window shape:

BB/BB/W+ W/+

That's four window panels B followed by a row of window characters and a column of window characters. Note that we make no explicit assertion that the four window panels are the same size, but if they aren't it's impossible to concatenate them into rectangle.

Finally the e` at the beginning is simply a configuration which tells Grime to check that the entire input can be matched by this pattern (and it prints 0 or 1 accordingly).


Perl, 124 123 119 95 93 84

The following Perl script reads one candidate MS Window from the standard input. It then exits with a zero exit status if the candidate is an MS Window and with a non-zero exit status if it isn't.

It works by generating two regular expressions, one for the top, middle and bottom line and one for every other line, and checking the input against them.

Thanks, @Dada. And again.

map{$s=$"x(($.-3)/2);$m="[MS]";($c++%($#a/2)?/^$m$s$m$s$m$/:/^${m}{$.}$/)||die}@a=<>