55
\$\begingroup\$

A string is considered to be square if the following conditions are met:

  • Each line has the same number of characters
  • The number of characters on each line is equal to the number of lines.

Your task is to write a program or function which determines whether or not a given input string is a square.

You may require input to be delimited by your choice of LF, CR, or CRLF.

The newline character(s) are not considered part of the line's length.

You may require there to be or to not be a trailing newline in input, which doesn't count as an additional line.

Input is a string or 1D char array; it is not a list of strings.

You may assume input is non-empty and only contains printable ASCII, including spaces.

You must output a truthy value for square strings and a falsy one for other strings.

Truthy test cases:

foo
bar
baz
.
.s.
.ss
.s.
(s represents space)
ss
ss
(s represents space)
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa

Falsy test cases:

..
.
.


.
....


....
4444
333
22
333
333
abc.def.ghi

Note extra blank lines in some of the falsy cases.

This is - fewest bytes wins!

\$\endgroup\$
9
  • 1
    \$\begingroup\$ @mbomb007 I feel like the different winning criteria make this not a duplicate? "Golfiness" was one of the voting criteria but I don't think answers to that question will largely reflect on the ones here. \$\endgroup\$ Jun 6, 2017 at 22:12
  • 3
    \$\begingroup\$ @mbomb007 I'm voting to leave this question open because, while it is a subset of the other question, the other question is restricted to languages created specifically for that question. \$\endgroup\$ Jun 6, 2017 at 22:15
  • 2
    \$\begingroup\$ @mbomb007: That's not a duplicate, because that question asks you to design a language for the purpose of answering the question, rather than answering in an existing language. Very few of the answers here would be legal there. \$\endgroup\$
    – user62131
    Jun 6, 2017 at 22:29
  • 1
    \$\begingroup\$ @mbomb007: That's no reason to close this challenge, and give people nowhere to post their answers in pre-existing languages, though. It might potentially be an argument for closing the other challenge (because it's just a more restrictive version of this one), although I'd consider it a poor argument and believe both should be left open. \$\endgroup\$
    – user62131
    Jun 7, 2017 at 17:47
  • 1
    \$\begingroup\$ Technically, the first requirement is redundant as it can never be false if the second is true. \$\endgroup\$
    – Antti29
    Jun 9, 2017 at 9:13

63 Answers 63

2
\$\begingroup\$

PowerShell, 48 bytes

($a=$args-split'
'|%{$_.Length}).Count-eq($a|gu)

Test script:

$f = {

($a=$args-split'
'|%{$_.Length}).Count-eq($a|gu)

}

@(

,($true,@"
foo
bar
baz
"@)

,($true,@"
.
"@)

,($true,@"
. .
.  
. .
"@)

,($true,@"


"@)

,($true,@"
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
"@)

,($false,@"
..
.
"@)

,($false,@"
.

"@)

,($false,@"

.
"@)

,($false,@"
....


....
"@)

,($false,@"
4444
333
22
"@)

,($false,@"
333
333
"@)

,($false,@"
abc.def.ghi
"@)

) | % {
    $expected,$s = $_
    $result = &$f $s
    "$($result-eq$expected): $result"
}

Output:

True: True
True: True
True: True
True: True
True: True
True: False
True: False
True: False
True: False
True: False
True: False
True: False

Explanation:

  • $args-split"``n"|%{$_.Length} creates an array of length of each line.
  • $a.Count counts elements of the array
  • $a|gu apply Get-Unique to the array. The result is one integer element if all lines has same length.
  • $a.Count-eq($a|gu) compares Count of element with result of the Get-Unique. It's true if all lines has same length and this length equals to Count.
\$\endgroup\$
2
\$\begingroup\$

Vyxal, 5 bytes

¶o²⁋=

Try it Online!

¶o²⁋=
¶o    # Remove all newlines
  ²   # Format as a square
   ⁋  # Join by newlines
    = # Equal to the input?
\$\endgroup\$
2
\$\begingroup\$

Pip, 11 bytes

Y0MMa^ny=Zy

Takes a multiline string (with no trailing newline) as a command-line argument. Try It Online!

Explanation

Y0MMa^ny=Zy
    a        Command-line argument
     ^n      Split on newlines
  MM         To each character of each line, map:
 0           0
             This results in a nested list of 0's, one for each character
Y            Yank it into the y variable
       y=    That nested list equals
         Zy  Its transpose

For example, with inputs "abc\ndefg" and "ab\ncd":

    a^n      ["abc";"defg"]       ["ab";"cd"]
Y0MM         [[0;0;0];[0;0;0;0]]  [[0;0];[0;0]]
         Zy  [[0;0];[0;0];[0;0]]  [[0;0];[0;0]]
       y=    0                    1
\$\endgroup\$
2
  • \$\begingroup\$ This gives a false negative when spaces are in certain places, including a square made entirely of spaces (test case #4) and any square with spaces only in its last line. \$\endgroup\$
    – Deadcode
    Jul 29, 2022 at 8:48
  • 1
    \$\begingroup\$ @Deadcode Input containing spaces needs to be wrapped in quotes. I updated the DSO link to reflect that. \$\endgroup\$
    – DLosc
    Jul 29, 2022 at 16:01
2
\$\begingroup\$

Scala, 42 39 bytes

Fairly compact, yet easily understandable

Saved 3 bytes thanks to @Steffan.

39 bytes solution using Java 8 Try it online!

s=>s.lines.forall(_.size==s.lines.size)

42 bytes solution using Java 11 or newer Try it online!

s=>s.lines.allMatch(_.size==s.lines.count)
\$\endgroup\$
6
  • 1
    \$\begingroup\$ By our meta consensus, you can't take input from a variable. You could instead use an anonymous function and prepend s->, though. \$\endgroup\$
    – naffetS
    Jul 29, 2022 at 18:36
  • 1
    \$\begingroup\$ noted, thank you @Steffan \$\endgroup\$ Jul 30, 2022 at 14:18
  • \$\begingroup\$ Here's an ATO link for testing this code: Try it online! \$\endgroup\$
    – naffetS
    Jul 30, 2022 at 15:49
  • \$\begingroup\$ Also, this only works in Scala 2 for me, because lines returns an Iterator instead of a Stream in Scala 3. You can save 3 bytes by using Scala 3, though: Try it online! \$\endgroup\$
    – naffetS
    Jul 30, 2022 at 15:52
  • \$\begingroup\$ This is interesting. Its not Scala but Java version that is causing the issue, it is the same reason for your shorter solution to be possible. Scala uses Java types and strings are no exception but they are implicitly converted to StringOps class which provides richer API. Scala first introduced StringOps.lines (returns Iterator) , however Java 11 added String.lines (returns Stream). forall is available only if you use Iterator. lines will implicitly return Iterator only if Java version < 11. @Steffan tio uses Scala 2.10.6, Java 8, ato uses Scala 2.13.8, Java 18 \$\endgroup\$ Jul 30, 2022 at 18:40
2
\$\begingroup\$

Regex (.NET), 55 bytes

^.((.))*(?<-1>
.(?=(?<-2>.)*(?(2).)
)(?<2>.)*)*$(?(1).)

Try it on regex101

Neil said in his Retina answer, "It could be done without, but this is code golf, not code challenge." Well, here's a pure regex answer that needs to do it that way (without substitutions done beforehand to lighten the load).

The last line must end with exactly one newline. To remove this restriction would result in worse golf.

In this explanation, indicates a raw newline in the regex:

^                    # Anchor to start of string
.                    # Skip one character, due to the fact that when we count
                     # the number of rows, matching it up with our capture count,
                     # the first row won't becounted.
((.))*               # Add the remaining length of this line to the capture count
                     # of both \1 and \2.
(?<-1>               # If there is at least one capture on the \1 stack, do the
                     # following:
    ¶                # Advance to the next line (thus proving that the entire
                     # previous line was processed)
    .                # Advance by one character (because we already did the same
                     # on the first line)
    (?=              # Lookahead - allows the same part of the string to be
                     # matched in multiple ways.
        (?<-2>.)*    # For each capture remaining on the \2 stack, advance one
                     # character. Will stop short if it reaches the end of the
                     # line before the \2 stack is emptied.
        (?(2).)¶     # Assert that if the \2 stack is not empty, there is at
                     # least one more character remaining in this line, but also
                     # assert that this is the end of the line - effectively
                     # asserting that the \2 stack is empty and we're at the end
                     # of the line.
    )
    (?<2>.)*         # Having already proved that this line is of equal length to
                     # the previous, transfer its length back into the capture
                     # count of group \2.
)*                   # Iterate the above as many times as possible, minimum zero.
$                    # Assert that we've reached the end of the string, or a
                     # newline after which it is the end of the string.
(?(1).)              # Effectively assert that the \1 stack is empty, as it is
                     # impossible to match one more non-newline character after
                     # reaching the end of the string.

Regex (Perl / PCRE2), 69 64 bytes

^(?=((?|
()|.(?=.*
(\2?+.)))+)+
\2$)((?=^|.+(\4?+
.+)).)+\4$|^.$

Try it online! - Perl
Try it on regex101 - PCRE2

A trailing newline on the last line is optional. Squares with or without it will both match. (In the 69 byte version, the trailing newline was mandatory.)

In PCRE, acceptance of a trailing newline can be disabled with a flag: Try it on regex101
But in Perl, the only way to do this is to replace $ with \z (+1 byte): Try it online!

The regex does not work in PCRE1 (the older and no longer maintained version of PCRE) due to a PCRE1 bug in which \2, a nested backreference, is not reverted to its earlier value when backtracking, causing it to have false positives on shapes that have an equal number of lines as characters in their first line, but whose remaining lines monotonically increase (or stay the same) in length.

In this explanation, indicates a raw newline in the regex:

^                          # Anchor to start of string
(?=                        # Lookahead - allows the same part of the string to
                           # be matched in multiple ways.
    # Assert this is a rectangle (all lines have an equal number of characters)
    # with at least 2 lines. A trailing newline on the last line is optional.
    (
        (?|                # Branch Reset Group - allows the same group numbers
                           # to be captured in different parts of the regex.
            # This alternative is to be taken when the inner loop has reached
            # the end of a line, finishing this iteration of the outer loop.
            ¶
            ()             # \2 = empty, in preparation for the next iteration
                           #      of the outer loop
        |
            # This alternative is to be taken while still processing the line.
            .              # Go forward one character.
            (?=            # Lookahead - match what's inside, then jump back to
                           # this position upon exiting it.
                .*¶        # Skip to the next line
                (          # \2 = the following:
                    \2?+   # Match previous value of \2 if set
                    .      # Match one extra character in this line
                )
            )
        )+                 # Iterate the above as many times as possible
    )+                     # Iterate the above as many times as possible
    ¶                      # Match a newline. Note that the regex engine will
                           # be forced to backtrack, because it will have
                           # already matched this newline inside the loop, and
                           # erased the contents of \2. Backtracking allows it
                           # to undo this, restoring the contents of \2 and
                           # allowing us to match the newline and \2 here.
    \2$                    # Assert that the last line is not longer than the
                           # penultimate line, by asserting that the string
                           # ends after the \2 that was captured. Note that "$"
                           # will match whether this is the end of the string,
                           # or a newline followed by the end of the string.
                           # "\z" only matches at the exact end of the string,
                           # but we don't need to use it.
)
# Assert the number of characters in the first line equals the number of lines
(
    (?=                    # Lookahead
        ^                  # On the leftmost character, match nothing else.
    |                      # On all subsequent characters, do the following:
        .+                 # Skip to the end of this line
        (                  # \4 = the following:
            \4?+           # Match previous value of \4 if set
            ¶.+            # Match a newline, followed by one more entire line,
                           # which we assert is at least one character long.
        )
    )
    .                      # Go forward one character.
)+                         # Iterate the above as many times as possible
\4$                        # Assert that the string ends after \4.

|^.$                       # Or, match a 1×1 square, which the above code can't
                           # do. Again, a trailing newline is optional due to
                           # the behavior of "$".
\$\endgroup\$
2
  • \$\begingroup\$ For my own edification, these regex engines are not "pure" DFA's, and a true regular language (in the computer science sense) couldn't solve this problem -- is that accurate? \$\endgroup\$
    – Jonah
    Jul 30, 2022 at 21:53
  • 1
    \$\begingroup\$ @Jonah That is correct. Lookaheads together with backreferences extend it beyond being a true regular language. \$\endgroup\$
    – Deadcode
    Jul 30, 2022 at 22:20
2
\$\begingroup\$

Julia 1.0, 42 bytes

!x=(y=split(x,"
");~=length;all(~y.==.~y))

Try it online!

This function splits the string over newlines and checks if the number of lines is equal to the length of each line. Since length must be called twice (vectorized and non-vectorized), it is renamed as ~ (Thanks amelies!).

\$\endgroup\$
4
  • \$\begingroup\$ Not sure this answers the topic question \$\endgroup\$
    – amelies
    Oct 9, 2022 at 15:34
  • \$\begingroup\$ @amelies You're right, thanks! I pasted in the solution to a different question by mistake. \$\endgroup\$ Oct 9, 2022 at 17:52
  • 1
    \$\begingroup\$ No problems! You can save one byte by replacing \n with a CR \$\endgroup\$
    – amelies
    Oct 9, 2022 at 18:00
  • 1
    \$\begingroup\$ Renaming length you can get to 40 bytes. Very good solution, I doubt I can golf more mine to beat this! \$\endgroup\$
    – amelies
    Oct 9, 2022 at 18:52
1
\$\begingroup\$

Cheddar, 39 bytes

@.split("
").all((i,j,k)->i.len==k.len)

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Clojure, 58 bytes

#(let[s(re-seq #"[^\n]+"%)c count](apply =(c s)(map c s)))

Requires a trailing newline, looking forward to seeing something more magical.

\$\endgroup\$
1
\$\begingroup\$

APL (Dyalog), 17 bytes

Requires ⎕ML←3 which is default on many systems. Uses CR.

↓∘⎕FMT≡⎕TC[2]∘≠⊂⊢

Try it online!

↓∘⎕FMT [is the] split-into-lines Formatted-into-a-square argument

 identical to

⎕TC[2]∘≠ the into-groups-of-non-newline*-characters

 partitioned

 argument?

* the second element of the list of Terminal Control characters.


In version 16.0, one can write ↓∘⎕FMT≡⎕TC[3]∘≠⊆⊢ with ⎕ML←1.

\$\endgroup\$
2
  • \$\begingroup\$ Curious, what's ⎕ML? \$\endgroup\$
    – Pavel
    Jun 6, 2017 at 23:51
  • 1
    \$\begingroup\$ @Phoenix In Dyalog APL and APL+, Migration Level is a rough measure for the dialectical movement in direction of IBM's APL2. The higher the number, the more APL2-like does the language become. People migrating from APL2 to other APLs tend to run with a high ⎕ML, while people who started with the other APLs tend to run with a low ⎕ML. \$\endgroup\$
    – Adám
    Jun 6, 2017 at 23:55
1
\$\begingroup\$

PowerShell, 64 bytes

The same (split, line lengths, number of lines) approach as other non-golf language answers, but there's no nice map() equivalent, so it's an array of line lengths with the number of lines tagged onto the end, then that array is grouped. Squares come out like 3,3,3,3 -> 1 group, all line lengths and line count were equal and non-squares come out like 3,2,1 -> 3 groups, something was unequal in the square:

$f={@(@(($L="$args"-split"`n")|% le*)+$L.Count|group).Count-eq1}

Requires newline Linux-style endings, no trailing newline. e.g.

$Ttests = @(@'
foo
bar
baz
'@,
'.',
@'
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
'@
)
$Ttests = $Ttests | foreach {$_ -replace "`r"}

$Ttests | % { & $f $_ }

(And you can do similar for the false tests, but I won't put it here as there's more of them). The couple of @ symbols are required for when the input is the single '.' otherwise splitting it doesn't make an array of one string it just makes one string, and then the array concatenation doesn't output 1,1 it outputs 2.

I hoped it might be shorter to replace all the characters with 'a', and then brute force from 1 to Input Length all the squares 'a' and see if any matched the input. Once I got past param() and .Length and -join and -replace it ends up much longer at 81 bytes:

$f={param($s)!!(1..$s.Length|?{,('a'*$_)*$_-join"`n"-eq($s-replace"[^`n]",'a')})}
\$\endgroup\$
1
\$\begingroup\$

Grime, 11 bytes

e`.|_./+/.+

Prints 1 for squares and 0 for non-squares. Try it online!

Explanation

A detailed explanation can be found on the Grime tutorial page, which happens to contain this exact program as an example.

e`.|_./+/.+
e`            Match entire input against pattern:
  .           A single character
   |          OR
    _         a recursive match of this pattern
     ./+      with one column of characters on its right
        /     and below that
         .+   one row of characters.
\$\endgroup\$
1
\$\begingroup\$

Dart - 54 chars

q(s)=>!(s=s.split('\n')).any((x)=>x.length!=s.length);

(Expects input separated by newlines and not terminated by one)

Try it online

\$\endgroup\$
1
\$\begingroup\$

C#, 73 bytes

using System.Linq;s=>s.Split('\n').All(l=>l.Length==s.Split('\n').Length)

Explanation:

using System.Linq;    //Import Linq
s=>                   //Take input
s.Split('\n')         //Split the input stirng by line feeds
.All(l=>              //Make sure All lines in the array return true for:
l.Length              //The length of the line
==                    //Equaling
s.Split('\n').Length) //The length of the array split again by line feeds
\$\endgroup\$
1
\$\begingroup\$

Clojure, 42 chars

#(every?(fn[x](=(count %)x))(map count %))
\$\endgroup\$
1
\$\begingroup\$

Charcoal, 20 bytes

A⁺№θ¶¹αF⪪θ¶A×α⁼αLιαα

Try it online! Prints - repeated by the side length as truthy, nothing as falsy.

\$\endgroup\$
1
\$\begingroup\$

><>, 76 bytes

This should work, next step is trying to golf it more!

0v      0   <
 >i:0)?!va=?^1+
:0)?v1n;\~l:   >
    >r:@=?!vr1-^
        ;n0<

Try it online! Or more more fun, try some examples using this animated interpreter.

printf "aaa\naas\naaa" | fish _square.fish --tick 0.1 --play

Explanation

The idea is roughly as follows.

  1. Fill the stack with the number of characters on each line.
  2. Push the length of the stack, corresponding to the number of lines (n).
  3. Do n times:
    • Check if bottom two elements are equal.
    • Remove deepest element.

Examples

For

aaa
aaa
aaa

we get [3, 3, 3, 3] after the first two steps and we can see that all three length 2 subsequences are equal. However, for

aaa
aa
a

we get [3, 2, 1, 3] and not all sequences are equal. For the last falsy case

`abc.def.ghi`

we get [11, 1] so there is only subpair we can check, but it is unequal so we return falsy.

\$\endgroup\$
1
\$\begingroup\$

Add++, 45 bytes

D,g,@,bU10C€=sVcG1+V10CAtbU€bLB]db=$bM*G=

Try it online!

How it works

Boy this was a long one (not even counting the footer)

D,g,@,		; Declare a monadic function 'g'
		; Example argument:    		 ['foo\nbar\nbaz']
	bU	; Unpack;		 STACK = ['f' 'o' 'o' '\n' 'b' 'a' 'r' '\n' 'b' 'a' 'z']
	10C€=s	; Count newlines;	 STACK = ['f' 'o' 'o' '\n' 'b' 'a' 'r' '\n' 'b' 'a' 'z' 2]
	VcG	; Keep last value;	 STACK = [2]
	1+V	; Increment and save;	 STACK = []			; STORE = 3
	10CAt	; Split arg on newlines; STACK = [['foo' 'bar' 'baz']]
	bU€bLB]	; Length of €ach;	 STACK = [[3 3 3]]
	db=	; Are they all equal?	 STACK = [[3 3 3] 1]
	$bM	; Max value;		 STACK = [1 3]
	*	; Logical AND;		 STACK = [3]
	G=	; Equals STORE?		 STACK = [1]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

PHP, 65 bytes

while(~$c=$argv[1][$p++])$w+=":"^$c||$w=!$$w+=!!++$h;echo$$h==$h;

expects linux style line endings (\n) and a trailing newline; prints 1 for truthy, nothing for falsy.
Run with php -nr '<code>' '<input>' or try it online.


Btw: The naive approach takes 82 bytes:

<?=count($a=explode("
",$argv[1]))==min($m=array_map(strlen,$a))&min($m)==max($m);

expects linebreaks as on compile system and no trailing newline; prints 1 or 0.
Run with php -nR '<code>' '<input>'.

\$\endgroup\$
1
\$\begingroup\$

Python 3, 79 bytes

lambda a:len(set([len(list(i))for i in a.split('\n')]+[len(a.split('\n'))]))==1
\$\endgroup\$
1
\$\begingroup\$

Swift 3, 134 bytes

import Foundation;func r(s:String)->Bool{let i=s.components(separatedBy:"\n");return i.filter{$0.characters.count != i.count}.isEmpty}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Wren, 76 61 bytes

Fn.new{|a|a.split("\n").all{|x|x.count==a.split("\n").count}}

Try it online!

Old answer

The algorithm is essentially just copied from a 05AB1E answer.

Fn.new{|a|
var b=a.split("\n").map{|i|i.count}
return b.all{|i|i==b.count}
}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Red, 73 bytes

func[s][all collect[foreach b a: split s lf[keep(length? b)= length? a]]]

Try it online!

{abcd efg} represents true multiline string and not a list of strings, hence I need split s lf

\$\endgroup\$
1
\$\begingroup\$

SnakeEx, 38 bytes

h:{c<B>1}{c<L>1}{e<>}{e<R>}
c:.+$
e:.$

A match is truthy; no match is falsey. Try it here


The previous 50-byte SnakeEx submission was copied from the original solution to the detect-square-inputs problem in the 2D pattern-matching language challenge. Here's the thing: that problem says, "Match the entire input if it is a square block of characters." But for this problem, we merely need to match something if the input is a square block of characters. That enables us to use a different approach, saving bytes.

Instead of matching the whole square, we match its bottom row and rightmost column and assert that they are the same length. (It's important to pick the rightmost column, since that will fail if we have jagged input.)

  • c:.+$ Define c to match some number of characters and then the edge of the grid
  • e:.$ Define e to match the character it's currently on and then the edge of the grid
  • {c<B>1} Turn backwards (i.e. toward the left side), match c, and put that match in group 1
  • {c<L>1} Turn left (i.e. toward the top), match c, and put that match in group 1 (thereby requiring both matches to be the same length)
  • {e<>} Match e in the default direction (toward the right side)
  • {e<R>} Turn right (i.e. toward the bottom) and match e

The two c calls make sure the height and width are the same; the two e calls make sure our starting point is the bottom right corner.

\$\endgroup\$
1
\$\begingroup\$

Google Sheets, 47

Closing parens/quotes already discounted.

Input: A1

A2 to A3:

=ArrayFormula(LEN(SPLIT(A1,"
")))
=A2=COUNTIF(2:2,A2)
\$\endgroup\$
1
\$\begingroup\$

05AB1E, 7 bytes

.B¤g∍»Q

Try it online or verify all test cases.

Explanation:

.B       # Box the (implicit) multi-line input-string, splitting on newlines,
         # and appended spaces to make all rows the same length
  ¤      # Push the last string (without popping the list)
   g     # † Pop and push its length
    ∍    # Extend/shorten the list up to this length
     »   # Join it by newlines
      Q  # Check if it's equal to the (implicit) input
         # (after which the result is output implicitly)

† This is only necessary if the last line of the input is a number. Builtin will extend/shorten it to the number size if a number is given as argument, but will use the length to extend/shorten if a string is given. E.g. "ab" "abcdefg" ∍ will extend the "ab" to length("abcdefg")=7, resulting in "abababa", but unfortunately "123" "12" ∍ will extend the "123" to "123123123123" instead of shortening it to length("12")=2 to "12".
So for all given test cases .B¤∍»Q would have sufficed, but unfortunately it'll fail for something like 123\nabc\n7.3.

\$\endgroup\$
1
\$\begingroup\$

BQN, 15 bytes

>∘⊔'
'⊸(≠×1+`=)

Anonymous tacit function. Takes a multiline string that must include a trailing newline. Try it at BQN online!

Outputs via error for falsey and no error for truthy. If that's not acceptable, here's a 19-byte version that returns 0 for falsey and 1 for truthy:

≡·>⎊0·⊔'
'⊸(≠×1+`=)

Explanation

>∘⊔'¶'⊸(≠×1+`=)
       (      )   Call this function with the multiline string as right argument
   '¶'⊸           and a newline character as left argument:
             =      For each character in the string, 1 if it is newline, 0 otherwise
           +`       Cumulative sum of that array
          1         starting at 1
         ×          For each of those values, multiply by the corresponding value in:
        ≠           For each character in the string, 0 if it is newline, 1 otherwise
                  This transforms the first line into 1s, the second line into 2s, etc.,
                  and newlines into 0s
  ⊔               Group the indices of this list according to their values in the list
>∘                Attempt to convert that list of lists to a rectangular array
  • If not all lines in the input are the same length, the groups will have different lengths, and the conversion to an array will fail.
  • If the input is rectangular but not square, the newlines group will have a different length from the other groups, and the conversion will fail.
  • If the input is an N by N square, there will be a group representing N newlines and N groups representing N characters each, which will be successfully converted into an N+1 by N array.
\$\endgroup\$
1
\$\begingroup\$

APL, 10 or 8 bytes

(≢=(⌈/≢¨))

Input is an array of strings.

Explained:

(       ) fork (could be removed if assigned to a variable)
 ≢        amount of strings
  =       equals
   (⌈/ )  the maximum
     ≢¨   of each of the string's lengths
\$\endgroup\$
2
  • \$\begingroup\$ "Input is a string or 1D char array; it is not a list of strings." \$\endgroup\$
    – chunes
    Oct 8, 2022 at 20:16
  • \$\begingroup\$ But that's the closest i can get, i don't how to type new line. \$\endgroup\$
    – Joao-3
    Oct 8, 2022 at 20:21
1
\$\begingroup\$

Julia 1.0, 44 41 bytes

!s=(l=count(==('
'),s)+1)l==length(s)-l+1

Try it online!

\$\endgroup\$
0
\$\begingroup\$

SnakeEx, 50 bytes

This is BMac's solution to the problem for the 2D regex language design challenge.

m:{v<R>1}{h<>1}
v:${c<L>A1}+$
h:${c<R>A1}+$
c:$.+$

Try it online

\$\endgroup\$
0
\$\begingroup\$

J, 12 bytes

(*./=#)#;._2

Input requires trailing LF or CR.

Explanation:

  • ;._2 split into intervals and discard trailing atom
  • # count each group
  • (*./=#) is a fork which returns 0 (false) or 1 (true) if the LCM of the count of each group is equal to the count-of-counts

Tests

(*./=#)#;._2 'abc', LF, 'def', LF, 'ghi', LF   NB. 1 for well-formed input
(*./=#)#;._2 'abc', LF, 'def', LF, 'ghi'       NB. 0 because no trailing LF
\$\endgroup\$
7
  • \$\begingroup\$ How does it determine what the delimiter is..? And by the way, abc.def.ghi. should be falsy, so while clever, the delimiter trick is actually invalid. \$\endgroup\$
    – Pavel
    Jun 8, 2017 at 16:15
  • \$\begingroup\$ @Phoenix A test case to reflect that would be beneficial \$\endgroup\$ Jun 9, 2017 at 4:53
  • \$\begingroup\$ @Phoenix My answer used to just say "requires trailing delimiter" but I edited it to specifically call out either LF or CR. abc.def.ghi. would be truthy but abc.def.ghi.LF (trailing LF) would be falsy. \$\endgroup\$ Jun 9, 2017 at 19:28
  • 1
    \$\begingroup\$ The way I read the rules, since I can require that all inputs end in LF, then my program should never have the chance to either accept or reject inputs which don't end in LF. \$\endgroup\$ Jun 19, 2017 at 16:13
  • 1
    \$\begingroup\$ 15 Bytes for */(=#)#@>@cutLF, which only accepts LF as a delimiter, and does not require a trailing LF: */(=#)#@>@cutLF 'abc', LF, 'def', LF, 'ghi' returns 1 \$\endgroup\$ Mar 22, 2018 at 17:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.