Skip to content

Instantly share code, notes, and snippets.

@kobi
Last active June 6, 2022 10:39
Show Gist options
  • Save kobi/b126088b26dacba2719e49045e0b79f9 to your computer and use it in GitHub Desktop.
Save kobi/b126088b26dacba2719e49045e0b79f9 to your computer and use it in GitHub Desktop.
using System.Text.RegularExpressions;
using System;
const string smallRectangles = "1\n\n2\n\n~~\n\n";
Regex normal = new Regex(Rect.RectanglesPatternShorter, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
Regex compiled = new Regex(Rect.RectanglesPatternShorter, RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
Console.WriteLine("normal: " + normal.IsMatch(smallRectangles));
Console.WriteLine("compiled: " + compiled.IsMatch(smallRectangles));
public static class Rect {
public const string RectanglesPatternShorter = @"
\A
(?=(?<NextPos>[^~]*)) # \k<NextPos> always matches the position *before* the next free tilde.
(?:
(?:
(?<IndexLength>.)+? # Match n characters. We will use rectangle number n in position <Index>.
# 0 is not an option - we need some shape to be first, second, third, etc.
(?<=\A(?=(?<Index>(?<-IndexLength>.)+)).*) # Capture into <Index> the first n characters.
(?<=\A(?<CurrentIndex>\k<Index>).*) # Copy Index into CurrentIndex
(?=.*\Z # Ensure <Index> is unique. We cannot use the same rectangle twice
(?<!(?=\A\k<Index>(?<=\A\k<CurrentIndex>))\A.*(?<-Index>.)+)
)
#Copy the shape of rectangle <Index> to the target area.
#Find rectangle number <Index>
(?<=(?=.(?<IndexLength>.)*?(?<=\A\k<Index>))\A.*) # Populate <IndexLength> again.
# ^-- we are skipping over one character. We want to reach rectangle number <IndexLength>,
# so we're skiping over <IndexLength>-1 rectangles
(?<=(?=\s*(?<-IndexLength>(?:\w+\r?\n)+\r?\n)*(?<=(?<RectangleStart>.*))\w)\A.*) # Capture starting position of this rectangle.
(?(IndexLength)(?!))
(?<=(?=\k<NextPos>(?<=(?<X>~*)))\A.*) # Init <X> with the number of tildes to the left of the starting position.
# Basically `(?:\w+\n)+\n` to match the whole rectangle.
(?<=(?=\k<RectangleStart> # Go to the position before the first character in the current rectangle.
\w+
\r?\n
\r?\n # Match until we reach the end of this rectangle.
)\A.*)
# Try to fit the rectangle into empty positions in the target rectangle.
(?<=(?=\k<NextPos>
(?: # Match tildes
~
(?<=(?<Filled>\A.*)) # Push the current position to <Filled>
)+?
(?<=^\k<X>~) # Match exactly <Width> tildes.
)\A.*)
# Find the next free position - <NextPos>.
(?<=(?=.*?
(?<=(?<NextPos>\A.*)) # <NextPos> is the position before the next free tilde.
~
(?<=(?<TempNextPos>\A.*)) # We compare it to <Filled>, which is the position including the tilde.
(?=.*\Z
(?<!(?=\A\k<Filled>(?<=\A\k<TempNextPos>))\A.*(?<-Filled>.)*)
)
|
.*\r?\n\Z (?<Done>) # If we cannot find more empty positions it means we are done. Set the <Done> flag.
)\A.*)
)
)+
(?(Done)|(?!))
";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment