Perl is pretty awesome for parsing text 'n stuff but if you wanna start learning something, Python is probably the answer. Especially if you want to start a career. From what I've seen, almost no one asks for Perl these days.
"Do not use the following reserved names for the name of a file:
CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. Also avoid these names followed immediately by an extension; for example, NUL.txt is not recommended."
I feel like I'm missing some context, but all I saw two pages back was the statement "C doesn't have an assert function" and I thought I was maybe, finally, going nuts, because: https://linux.die.net/man/3/assert
POSIX.1-2001, C89, C99. In C89, expression is required to be of type int and undefined behavior results if it is not, but in C99 it may have any scalar type.
I know Windows is wonky sometimes, but it was in C89, so...
"Do not use the following reserved names for the name of a file:
CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. Also avoid these names followed immediately by an extension; for example, NUL.txt is not recommended."
The twitter thread goes into some details, but basically (if I read this correctly) it's due to how the major OS in the 70s treated everything as a file, so things that are services (like the printer port) were prevented from having files that shared that name. DOS inherited that for backwards compatibility and... well, never changed it.
The user here was copying a file from Linux, which doesn't have that "feature" and Windows denied it.
It's a thowback to CP/M where the thing before the colon was the IO Device. Now we just use the drive letters. I kind of wish that Windows would just ditch the letters for a generic file:// type and mount drives as folders like Linux.
I remember that in windows 95, "copy con: con:" would immediately bluescreen the system. This was the heyday of autorun media so that was an absolute hoot to deal with.
How to match "A B C" where A+B=C: The Beast Reborn
A while ago, I created a regex to verify addition of two non-negative integers, and unleashed the unholy mess onto reddit. Reactions were fierce, heads exploded, etc. and so I immediately took to demystifying it by introducing line breaks, comments, and structured formatting. This follow-up was so effective that many commenters were lulled to a state of boredom by the result, underwhelmed by its simplicity. The loudest voices expressed dissatisfaction with the robustness of the solution, complaining about the lack of negative number support and, worse yet, the stark absence of decimal support.
Slowly, I came to realize that these people were right. These features needed to be implemented; the regex simply wasn’t long and complicated enough. So I returned to the drawing board, puked on it several times, and ended up with the following:
# A slow start
^
# Immediately step on the gas
# Parse expression as before, but with some extra pizzazz
(?=[-+]?(?:0\B)*+(\d*?)((?:(?=\d+(?:\.\d+)?\ [-+]?(?:0\B)*+(\d*?)(\d(?(4)\4))(?:\.\d+)?\ [-+]?(?:0\B)*+(\d*?)(\d(?(6)\6))(?:\.\d+)?$)\d)++)\b)
(?:
# 0th case: handle 0 + 0 = 0 with any sign orientation
^(?:[-+]?0+(?:\.0+)?(?:\ |$)){3}\b$
|
# 1st case: handle "A B C" and "-A -B -C", ie. check A+B=C
(?=-\S*\ -\S*\ -|(?!.*-))
[-+]?(?:0\B)*+
# Check leading excess digits
(?=
(?(?!\1\.?(?!(?!(?&a))))
# No carrying, match one excess part to the other
(?=\S+\ \S+\ [-+]?0*\1\3\6(?:\.\d+)?$)
|
# Carrying, match one excess part to 1 + the other
(?(?!.*+\3)\S+\ [-+]?(?:0\B)*)
(?=\d*?(\2|\4)\b(.*?\ [-+]?(?:0\B)*)\S+$)
# Check for carrying with all 9s
(?(?=9*\7\b)
# If so, match '9's to '0's and check for a leading '1'
(?:9(?=\d*?\8[1](\g{-1}?+0)))*?
\7\8[1]\g{-1}?+\6\b
|
# Otherwise, match equivalent pairs of digits until they differ by 1
# Then pair any extra '0's with '9's
(?:(\d)(?=\d*\8(\g{-1}?+\g{-2})))*+
(?=\d(\d*\8\g{-2}?+))
(?=0\g{-1}1|1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9)
\d
(?:9(?=\d*\8\g{-2}?+\d(\g{-1}?+0)))*?
\7\8\g{-3}?+\d\g{-1}?+\6\b
)
)
)
\1
# Check rest of digits
(?:
# Identify next group of digits to examine
(?=\.?(\d)\S*\ [-+]?(?:0\B)*+\3((\g{-2}?+\.?)\d)\S*\ [-+]?(?:0\B)*+\5((\g{-2}?+\.?)\d))
\.?(*SKIP)
# Check for carrying and match digits accordingly
(?(?=(?!
\14\.?
(?<a>
# Match pairs of digits that totals 9
(?:
(?=\d\.?\d(?<b>\S*?\ [-+]?(?:0\B)*\3\15?+)((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d\.?(?=\S*?(\g{-5}\g{-4}))
)*+
# Match a pair of digits that totals > 9
(?=\d(\g{-2}\.?|(?&b)\.?))
(?=[5-9]\g{-1}[5-9]|1\g{-1}9|2\g{-1}[89]|3\g{-1}[7-9]|4\g{-1}[6-9]|6\g{-1}4|7\g{-1}[34]|8\g{-1}[2-4]|9\g{-1}[1-4])
){0}
# Backreferences were erroneously being set that carried over to subsequent iterations,
# necessitating this subroutine call
# PCRE really wanted me to fail, apparently
(?&a)
))
# No carrying, match pairs of digits and their sums
# My goodness it's beautiful
(?=\d(\S*\ [-+]?(?:0\B)*\3\16)\d(\S*\ [-+]?(?:0\B)*\5\18))
(?=
1\g{-2}(?:1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9|9\g{-1}0)
|2\g{-2}(?:1\g{-1}3|2\g{-1}4|3\g{-1}5|4\g{-1}6|5\g{-1}7|6\g{-1}8|7\g{-1}9|8\g{-1}0|9\g{-1}1)
|3\g{-2}(?:1\g{-1}4|2\g{-1}5|3\g{-1}6|4\g{-1}7|5\g{-1}8|6\g{-1}9|7\g{-1}0|8\g{-1}1|9\g{-1}2)
|4\g{-2}(?:1\g{-1}5|2\g{-1}6|3\g{-1}7|4\g{-1}8|5\g{-1}9|6\g{-1}0|7\g{-1}1|8\g{-1}2|9\g{-1}3)
|5\g{-2}(?:1\g{-1}6|2\g{-1}7|3\g{-1}8|4\g{-1}9|5\g{-1}0|6\g{-1}1|7\g{-1}2|8\g{-1}3|9\g{-1}4)
|6\g{-2}(?:1\g{-1}7|2\g{-1}8|3\g{-1}9|4\g{-1}0|5\g{-1}1|6\g{-1}2|7\g{-1}3|8\g{-1}4|9\g{-1}5)
|7\g{-2}(?:1\g{-1}8|2\g{-1}9|3\g{-1}0|4\g{-1}1|5\g{-1}2|6\g{-1}3|7\g{-1}4|8\g{-1}5|9\g{-1}6)
|8\g{-2}(?:1\g{-1}9|2\g{-1}0|3\g{-1}1|4\g{-1}2|5\g{-1}3|6\g{-1}4|7\g{-1}5|8\g{-1}6|9\g{-1}7)
|9\g{-2}(?:1\g{-1}0|2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8)
|0\g{-2}(\d)\g{-2}\g{-1}
|(\d)\g{-4}0\g{-3}\g{-1}
)
|
# Carrying, match pairs of digits and their sums + 1
(?=\d((?-5))\d((?-5)))
(?=
1\g{-2}(?:0\g{-1}2|1\g{-1}3|2\g{-1}4|3\g{-1}5|4\g{-1}6|5\g{-1}7|6\g{-1}8|7\g{-1}9|8\g{-1}0|9\g{-1}1)
|2\g{-2}(?:0\g{-1}3|1\g{-1}4|2\g{-1}5|3\g{-1}6|4\g{-1}7|5\g{-1}8|6\g{-1}9|7\g{-1}0|8\g{-1}1|9\g{-1}2)
|3\g{-2}(?:0\g{-1}4|1\g{-1}5|2\g{-1}6|3\g{-1}7|4\g{-1}8|5\g{-1}9|6\g{-1}0|7\g{-1}1|8\g{-1}2|9\g{-1}3)
|4\g{-2}(?:0\g{-1}5|1\g{-1}6|2\g{-1}7|3\g{-1}8|4\g{-1}9|5\g{-1}0|6\g{-1}1|7\g{-1}2|8\g{-1}3|9\g{-1}4)
|5\g{-2}(?:0\g{-1}6|1\g{-1}7|2\g{-1}8|3\g{-1}9|4\g{-1}0|5\g{-1}1|6\g{-1}2|7\g{-1}3|8\g{-1}4|9\g{-1}5)
|6\g{-2}(?:0\g{-1}7|1\g{-1}8|2\g{-1}9|3\g{-1}0|4\g{-1}1|5\g{-1}2|6\g{-1}3|7\g{-1}4|8\g{-1}5|9\g{-1}6)
|7\g{-2}(?:0\g{-1}8|1\g{-1}9|2\g{-1}0|3\g{-1}1|4\g{-1}2|5\g{-1}3|6\g{-1}4|7\g{-1}5|8\g{-1}6|9\g{-1}7)
|8\g{-2}(?:0\g{-1}9|1\g{-1}0|2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8)
|9\g{-2}(?:0\g{-1}0|1\g{-1}1|2\g{-1}2|3\g{-1}3|4\g{-1}4|5\g{-1}5|6\g{-1}6|7\g{-1}7|8\g{-1}8|9\g{-1}9)
|0\g{-2}(?:0\g{-1}1|1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9|9\g{-1}0)
)
)
\d
)++
# Paths to success
(?:
# A, B and C contain no more significant digits
(?:\.0+)?0*\ [-+]?0*\3\15(?:\.0+)?0*\ [-+]?0*\5\17(?:\.0+)?0*$
|
# A contains no more significant digits, match B's excess to C's
\ [-+]?0*\3\15(\.?\d*?)0*\ [-+]?0*\5\17\g{-1}(?:\.0+)?0*$
|
# B contains no more significant digits, match A's excess to C's
(\.?\d*?)0*\ [-+]?0*\3\15\ [-+]?0*\5\17\g{-1}(?:\.0+)?0*$
|
# C contains no more significant digits but A and B both do
# Match pairs of digits that total 9 until one that totals 10 is found
\.?
(?:
(?=\d\d((?&b))((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d
(?=\S*?(\g{-5}(\g{-5})))
)*+
# Match a pair that totals 10 then validate
(?=\d(\g{-3}|(?&b)\.?))
(?=1\g{-1}9|2\g{-1}8|3\g{-1}7|4\g{-1}6|5\g{-1}5|6\g{-1}4|7\g{-1}3|8\g{-1}2|9\g{-1}1)
\d0*\ [-+]?0*\3\15\g{-2}?+\.?\d0*\ [-+]?0*\5\17\.?0*$
)
|
# Case 2: handle "-A B C" and "A -B -C", ie. check A+C=B
(?=-(?!.*-)|[^-]\S*\ -\S*\ -)
[-+]?(?:0\B)*+
# Check leading excess digits
(?=
(?(?!\1\.?(?!(?!(?&c))))
# No carrying, match one excess part to the other
(?=\S+\ [-+]?0*\1\5\4\b)
|
# Carrying, match one excess part to 1 + the other
# There are two paths here depending on whether |A| < |C| or |C| <= |A|
(?|
# |A| < |C|
(?!.++\5)
\S+\ [-+]?(?:0\B)*+(?=\S*(\ [-+]?(?:0\B)*+)())
# Check for carrying with all '9's
(?(?=\S*\41[9]*\6\b)
# If so, match '9's to '0's and check for a leading '1'
1(?:0(?=\S*\41(\g{-1}?+9)))*?
\4\b\S*\41\g{-1}?+\6\b
|
# Otherwise, match equivalent pairs of digits until they differ by 1
# Then pair any extra '0's with '9's
(?:(\d)(?=\S*\41(\g{-1}?+\g{-2})))*+
(?=\d(\S*\41\g{-2}?+))(?=1\g{-1}0|2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8)
\d
(?:0(?=\S*\41\g{-2}?+\d(\g{-1}?+9)))*?
\4\b\S*\41\g{-3}?+\d\g{-1}?+\6\b
)
|
# |C| <= |A|, basically the same comments as above
(?=.*+\5)
(?=\d*?(\2)\b(\S*\ [-+]?(?:0\B)*+))
(?(?=9*\41\b)
(?:9(?=\d*?\42[1](\g{-1}?+0)))*?
\41\42[1]\g{-1}?+\4\b
|
(?:(\d)(?=\d*\42(\g{-1}?+\g{-2})))*+
(?=\d(\d*\42\g{-2}?+))
(?=0\g{-1}1|1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9)
\d
(?:9(?=\S*\42\g{-2}?+\d(\g{-1}?+0)))*?
\41\42\g{-3}?+\d\g{-1}?+\4\b
)
)
)
)
\1
# Check rest of digits
(?:
# Identify next group of digits to examine
(?=\.?(\d)\S*\ [-+]?(?:0\B)*+\3((\g{-2}?+\.?)\d)\S*\ [-+]?(?:0\B)*+\5((\g{-2}?+\.?)\d))
\.?(*SKIP)
# Check for carrying and match digits accordingly
(?(?=(?!
\48\.?
(?<c>
# Match pairs of digits that totals 9
(?:
(?=\d\.?\d(?<d>\S*?\ \S+\ [-+]?(?:0\B)*\5\51?+)((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d\.?(?=\S*?(\g{-5}\g{-4}))
)*+
# Match a pair of digits that totals > 9
(?=\d(\g{-2}\.?|(?&d)\.?))
(?=[5-9]\g{-1}[5-9]|1\g{-1}9|2\g{-1}[89]|3\g{-1}[7-9]|4\g{-1}[6-9]|6\g{-1}4|7\g{-1}[34]|8\g{-1}[2-4]|9\g{-1}[1-4])
){0}
# Backreferences were erroneously being set that carried over to subsequent iterations,
# necessitating this silly subroutine call
(?&c)
))
# No carrying, match pairs of digits and their sums
(?=\d(\S*\ [-+]?(?:0\B)*\3\50)\d(\S*\ [-+]?(?:0\B)*\5\52))
(?=
1\g{-2}(?:2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8|0\g{-1}9)
|2\g{-2}(?:3\g{-1}1|4\g{-1}2|5\g{-1}3|6\g{-1}4|7\g{-1}5|8\g{-1}6|9\g{-1}7|0\g{-1}8|1\g{-1}9)
|3\g{-2}(?:4\g{-1}1|5\g{-1}2|6\g{-1}3|7\g{-1}4|8\g{-1}5|9\g{-1}6|0\g{-1}7|1\g{-1}8|2\g{-1}9)
|4\g{-2}(?:5\g{-1}1|6\g{-1}2|7\g{-1}3|8\g{-1}4|9\g{-1}5|0\g{-1}6|1\g{-1}7|2\g{-1}8|3\g{-1}9)
|5\g{-2}(?:6\g{-1}1|7\g{-1}2|8\g{-1}3|9\g{-1}4|0\g{-1}5|1\g{-1}6|2\g{-1}7|3\g{-1}8|4\g{-1}9)
|6\g{-2}(?:7\g{-1}1|8\g{-1}2|9\g{-1}3|0\g{-1}4|1\g{-1}5|2\g{-1}6|3\g{-1}7|4\g{-1}8|5\g{-1}9)
|7\g{-2}(?:8\g{-1}1|9\g{-1}2|0\g{-1}3|1\g{-1}4|2\g{-1}5|3\g{-1}6|4\g{-1}7|5\g{-1}8|6\g{-1}9)
|8\g{-2}(?:9\g{-1}1|0\g{-1}2|1\g{-1}3|2\g{-1}4|3\g{-1}5|4\g{-1}6|5\g{-1}7|6\g{-1}8|7\g{-1}9)
|9\g{-2}(?:0\g{-1}1|1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9)
|0\g{-2}(\d)\g{-2}\g{-1}
|(\d)\g{-4}\g{-1}\g{-3}0
)
|
# Carrying, match pairs of digits and their sums + 1
(?=\d((?-5))\d((?-5)))
(?=
1\g{-2}(?:2\g{-1}0|3\g{-1}1|4\g{-1}2|5\g{-1}3|6\g{-1}4|7\g{-1}5|8\g{-1}6|9\g{-1}7|0\g{-1}8|1\g{-1}9)
|2\g{-2}(?:3\g{-1}0|4\g{-1}1|5\g{-1}2|6\g{-1}3|7\g{-1}4|8\g{-1}5|9\g{-1}6|0\g{-1}7|1\g{-1}8|2\g{-1}9)
|3\g{-2}(?:4\g{-1}0|5\g{-1}1|6\g{-1}2|7\g{-1}3|8\g{-1}4|9\g{-1}5|0\g{-1}6|1\g{-1}7|2\g{-1}8|3\g{-1}9)
|4\g{-2}(?:5\g{-1}0|6\g{-1}1|7\g{-1}2|8\g{-1}3|9\g{-1}4|0\g{-1}5|1\g{-1}6|2\g{-1}7|3\g{-1}8|4\g{-1}9)
|5\g{-2}(?:6\g{-1}0|7\g{-1}1|8\g{-1}2|9\g{-1}3|0\g{-1}4|1\g{-1}5|2\g{-1}6|3\g{-1}7|4\g{-1}8|5\g{-1}9)
|6\g{-2}(?:7\g{-1}0|8\g{-1}1|9\g{-1}2|0\g{-1}3|1\g{-1}4|2\g{-1}5|3\g{-1}6|4\g{-1}7|5\g{-1}8|6\g{-1}9)
|7\g{-2}(?:8\g{-1}0|9\g{-1}1|0\g{-1}2|1\g{-1}3|2\g{-1}4|3\g{-1}5|4\g{-1}6|5\g{-1}7|6\g{-1}8|7\g{-1}9)
|8\g{-2}(?:9\g{-1}0|0\g{-1}1|1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9)
|9\g{-2}(?:0\g{-1}0|1\g{-1}1|2\g{-1}2|3\g{-1}3|4\g{-1}4|5\g{-1}5|6\g{-1}6|7\g{-1}7|8\g{-1}8|9\g{-1}9)
|0\g{-2}(?:1\g{-1}0|2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8|0\g{-1}9)
)
)
\d
)++
# Paths to success
(?:
# A, B, and C contain no more significant digits
(?:\.0+)?0*\ [-+]?0*\3\49(?:\.0+)?0*\ [-+]?0*\5\51(?:\.0+)?0*$
|
# A contains no more significant digits, match B's excess to C's
\ [-+]?0*\3\49(\.?\d*?)0*\ [-+]?0*\5\51\g{-1}(?:\.0+)?0*$
|
# C contains no more significant digits, match A's excess to B's
(\.?\d*?)0*\ [-+]?0*\3\49\g{-1}(?:\.0+)?0*\ [-+]?0*\5\51$
|
# B contains no more significant digits but A and B both do
# Match pairs of digits that totals 9 until one that totals 10 is found
\.?
(?:
(?=\d\d((?&d))((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d
(?=\S*?(\g{-5}(\g{-5})))
)*+
# Match a pair that totals 10 then validate
(?=\d(\g{-3}|(?&d)\.?))
(?=1\g{-1}9|2\g{-1}8|3\g{-1}7|4\g{-1}6|5\g{-1}5|6\g{-1}4|7\g{-1}3|8\g{-1}2|9\g{-1}1)
\d0*\ [-+]?0*\3\49\.?0*\ [-+]?0*\5\51\g{-2}?+\.?\d0*$
)
|
# And finally, handle "A -B C" and "-A B -C", ie. check B+C=A
(?=[^-]\S*\ -\S*\ [^-]\S*|-\S*\ [^-]\S*\ -)
[-+]?(?:0\B)*+
# Check leading excess digits
(?=
(?(?!\S+\ [-+]?(?:0\B)*+\3\.?(?!(?!(?&e))))
# No carrying, match one excess part to the other
(?=\3\5\2\b)
|
# Carrying, match one excess part to 1 + the other
(?=\d*(\S*\ (?(?=.*+\3)\S+\ )[-+]?(?:0\B)*+)\d*?(\4|\6)\b)
# Check for carrying with a leading '1' and all '0's
(?(?=10*\2\b)
# If so, match '0's to '9's
1(?:0(?=\d*\75(\g{-1}?+9)))*?
\2\b\75\g{-1}?+\76\b
|
# Otherwise, match equivalent pairs of digits until they differ by 1
# Then pair any extra '0's with '9's
(?:(\d)(?=\d*\75(\g{-1}?+\g{-2})))*+
(?=\d(\d*\75\g{-2}?+))
(?=1\g{-1}0|2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8)
\d
(?:0(?=\d*\75\g{-2}?+\d(\g{-1}?+9)))*?
\2\b\75\g{-3}?+\d\g{-1}?+\76\b
)
)
)
\1
# Check rest of digits
(?:
# Identify next group of digits to examine
(?=\.?(\d)\S*\ [-+]?(?:0\B)*+\3((\g{-2}?+\.?)\d)\S*\ [-+]?(?:0\B)*+\5((\g{-2}?+\.?)\d))
\.?(*SKIP)
# Check for carrying and match digits accordingly
(?(?=(?!
\S*\ [-+]?(?:0\B)*+\3\83\.?
(?<e>
# Match pairs of digits that totals 9
(?:
(?=\d\.?\d(?<f>\S*?\ [-+]?(?:0\B)*\5\85?+)((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d\.?
(?=\S*?(\g{-5}\g{-4}))
)*+
# Match a pair of digits that totals > 9
(?=\d(\g{-2}\.?|(?&f)\.?))
(?=[5-9]\g{-1}[5-9]|1\g{-1}9|2\g{-1}[89]|3\g{-1}[7-9]|4\g{-1}[6-9]|6\g{-1}4|7\g{-1}[34]|8\g{-1}[2-4]|9\g{-1}[1-4])
){0}
# Backreferences were erroneously being set that carried over to subsequent iterations,
# necessitating this preposterous subroutine call
(?&e)
))
# No carrying, match pairs of digits and their sums
(?=\d(\S*\ [-+]?(?:0\B)*\3\84)\d(\S*\ [-+]?(?:0\B)*\5\86))
(?=
(?:2\g{-2}1|3\g{-2}2|4\g{-2}3|5\g{-2}4|6\g{-2}5|7\g{-2}6|8\g{-2}7|9\g{-2}8|0\g{-2}9)\g{-1}1
|(?:3\g{-2}1|4\g{-2}2|5\g{-2}3|6\g{-2}4|7\g{-2}5|8\g{-2}6|9\g{-2}7|0\g{-2}8|1\g{-2}9)\g{-1}2
|(?:4\g{-2}1|5\g{-2}2|6\g{-2}3|7\g{-2}4|8\g{-2}5|9\g{-2}6|0\g{-2}7|1\g{-2}8|2\g{-2}9)\g{-1}3
|(?:5\g{-2}1|6\g{-2}2|7\g{-2}3|8\g{-2}4|9\g{-2}5|0\g{-2}6|1\g{-2}7|2\g{-2}8|3\g{-2}9)\g{-1}4
|(?:6\g{-2}1|7\g{-2}2|8\g{-2}3|9\g{-2}4|0\g{-2}5|1\g{-2}6|2\g{-2}7|3\g{-2}8|4\g{-2}9)\g{-1}5
|(?:7\g{-2}1|8\g{-2}2|9\g{-2}3|0\g{-2}4|1\g{-2}5|2\g{-2}6|3\g{-2}7|4\g{-2}8|5\g{-2}9)\g{-1}6
|(?:8\g{-2}1|9\g{-2}2|0\g{-2}3|1\g{-2}4|2\g{-2}5|3\g{-2}6|4\g{-2}7|5\g{-2}8|6\g{-2}9)\g{-1}7
|(?:9\g{-2}1|0\g{-2}2|1\g{-2}3|2\g{-2}4|3\g{-2}5|4\g{-2}6|5\g{-2}7|6\g{-2}8|7\g{-2}9)\g{-1}8
|(?:0\g{-2}1|1\g{-2}2|2\g{-2}3|3\g{-2}4|4\g{-2}5|5\g{-2}6|6\g{-2}7|7\g{-2}8|8\g{-2}9)\g{-1}9
|(\d)\g{-3}0\g{-2}\g{-1}
|(\d)\g{-4}\g{-1}\g{-3}0
)
|
# Carrying, match pairs of digits and their sums + 1
(?=\d((?-5))\d((?-5)))
(?=
(?:2\g{-2}0|3\g{-2}1|4\g{-2}2|5\g{-2}3|6\g{-2}4|7\g{-2}5|8\g{-2}6|9\g{-2}7|0\g{-2}8|1\g{-2}9)\g{-1}1
|(?:3\g{-2}0|4\g{-2}1|5\g{-2}2|6\g{-2}3|7\g{-2}4|8\g{-2}5|9\g{-2}6|0\g{-2}7|1\g{-2}8|2\g{-2}9)\g{-1}2
|(?:4\g{-2}0|5\g{-2}1|6\g{-2}2|7\g{-2}3|8\g{-2}4|9\g{-2}5|0\g{-2}6|1\g{-2}7|2\g{-2}8|3\g{-2}9)\g{-1}3
|(?:5\g{-2}0|6\g{-2}1|7\g{-2}2|8\g{-2}3|9\g{-2}4|0\g{-2}5|1\g{-2}6|2\g{-2}7|3\g{-2}8|4\g{-2}9)\g{-1}4
|(?:6\g{-2}0|7\g{-2}1|8\g{-2}2|9\g{-2}3|0\g{-2}4|1\g{-2}5|2\g{-2}6|3\g{-2}7|4\g{-2}8|5\g{-2}9)\g{-1}5
|(?:7\g{-2}0|8\g{-2}1|9\g{-2}2|0\g{-2}3|1\g{-2}4|2\g{-2}5|3\g{-2}6|4\g{-2}7|5\g{-2}8|6\g{-2}9)\g{-1}6
|(?:8\g{-2}0|9\g{-2}1|0\g{-2}2|1\g{-2}3|2\g{-2}4|3\g{-2}5|4\g{-2}6|5\g{-2}7|6\g{-2}8|7\g{-2}9)\g{-1}7
|(?:9\g{-2}0|0\g{-2}1|1\g{-2}2|2\g{-2}3|3\g{-2}4|4\g{-2}5|5\g{-2}6|6\g{-2}7|7\g{-2}8|8\g{-2}9)\g{-1}8
|(?:0\g{-2}0|1\g{-2}1|2\g{-2}2|3\g{-2}3|4\g{-2}4|5\g{-2}5|6\g{-2}6|7\g{-2}7|8\g{-2}8|9\g{-2}9)\g{-1}9
|(?:1\g{-2}0|2\g{-2}1|3\g{-2}2|4\g{-2}3|5\g{-2}4|6\g{-2}5|7\g{-2}6|8\g{-2}7|9\g{-2}8|0\g{-2}9)\g{-1}0
)
)
\d
)++
# Paths to success
(?:
# A, B, and C contain no more significant digits
(?:\.0+)?0*\ [-+]?0*\3\83(?:\.0+)?0*\ [-+]?0*\5\85(?:\.0+)?0*$
|
# C contains no more significant digits, match A's excess to B's
(\.?\d*?)0*\ [-+]?0*\3\83\g{-1}(?:\.0+)?0*\ [-+]?0*\5\85$
|
# B contains no more significant digits, match A's excess to C's
(\.?\d*?)0*\ [-+]?0*\3\83\ [-+]?0*\5\85\g{-1}(?:\.0+)?0*$
|
# A contains no more significant digits but B and C both do
# Match pairs of digits that total 9 until one that totals 10 is found
\.?0*\ [-+]?(?:0\B)*+\3\83\.?
(?:
(?=\d\d((?&f))((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d
(?=\S*?(\g{-5}(\g{-5})))
)*+
# Match a pair that totals 10 then validate
(?=\d(\g{-3}|(?&f)\.?))
(?=1\g{-1}9|2\g{-1}8|3\g{-1}7|4\g{-1}6|5\g{-1}5|6\g{-1}4|7\g{-1}3|8\g{-1}2|9\g{-1}1)
\d0*\ [-+]?0*\5\85\g{-2}?+\.?\d0*$
)
)
How to match "A B C" where A+B=C: The Beast Reborn
A while ago, I created a regex to verify addition of two non-negative integers, and unleashed the unholy mess onto reddit. Reactions were fierce, heads exploded, etc. and so I immediately took to demystifying it by introducing line breaks, comments, and structured formatting. This follow-up was so effective that many commenters were lulled to a state of boredom by the result, underwhelmed by its simplicity. The loudest voices expressed dissatisfaction with the robustness of the solution, complaining about the lack of negative number support and, worse yet, the stark absence of decimal support.
Slowly, I came to realize that these people were right. These features needed to be implemented; the regex simply wasn’t long and complicated enough. So I returned to the drawing board, puked on it several times, and ended up with the following:
# A slow start
^
# Immediately step on the gas
# Parse expression as before, but with some extra pizzazz
(?=[-+]?(?:0\B)*+(\d*?)((?:(?=\d+(?:\.\d+)?\ [-+]?(?:0\B)*+(\d*?)(\d(?(4)\4))(?:\.\d+)?\ [-+]?(?:0\B)*+(\d*?)(\d(?(6)\6))(?:\.\d+)?$)\d)++)\b)
(?:
# 0th case: handle 0 + 0 = 0 with any sign orientation
^(?:[-+]?0+(?:\.0+)?(?:\ |$)){3}\b$
|
# 1st case: handle "A B C" and "-A -B -C", ie. check A+B=C
(?=-\S*\ -\S*\ -|(?!.*-))
[-+]?(?:0\B)*+
# Check leading excess digits
(?=
(?(?!\1\.?(?!(?!(?&a))))
# No carrying, match one excess part to the other
(?=\S+\ \S+\ [-+]?0*\1\3\6(?:\.\d+)?$)
|
# Carrying, match one excess part to 1 + the other
(?(?!.*+\3)\S+\ [-+]?(?:0\B)*)
(?=\d*?(\2|\4)\b(.*?\ [-+]?(?:0\B)*)\S+$)
# Check for carrying with all 9s
(?(?=9*\7\b)
# If so, match '9's to '0's and check for a leading '1'
(?:9(?=\d*?\8[1](\g{-1}?+0)))*?
\7\8[1]\g{-1}?+\6\b
|
# Otherwise, match equivalent pairs of digits until they differ by 1
# Then pair any extra '0's with '9's
(?:(\d)(?=\d*\8(\g{-1}?+\g{-2})))*+
(?=\d(\d*\8\g{-2}?+))
(?=0\g{-1}1|1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9)
\d
(?:9(?=\d*\8\g{-2}?+\d(\g{-1}?+0)))*?
\7\8\g{-3}?+\d\g{-1}?+\6\b
)
)
)
\1
# Check rest of digits
(?:
# Identify next group of digits to examine
(?=\.?(\d)\S*\ [-+]?(?:0\B)*+\3((\g{-2}?+\.?)\d)\S*\ [-+]?(?:0\B)*+\5((\g{-2}?+\.?)\d))
\.?(*SKIP)
# Check for carrying and match digits accordingly
(?(?=(?!
\14\.?
(?<a>
# Match pairs of digits that totals 9
(?:
(?=\d\.?\d(?<b>\S*?\ [-+]?(?:0\B)*\3\15?+)((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d\.?(?=\S*?(\g{-5}\g{-4}))
)*+
# Match a pair of digits that totals > 9
(?=\d(\g{-2}\.?|(?&b)\.?))
(?=[5-9]\g{-1}[5-9]|1\g{-1}9|2\g{-1}[89]|3\g{-1}[7-9]|4\g{-1}[6-9]|6\g{-1}4|7\g{-1}[34]|8\g{-1}[2-4]|9\g{-1}[1-4])
){0}
# Backreferences were erroneously being set that carried over to subsequent iterations,
# necessitating this subroutine call
# PCRE really wanted me to fail, apparently
(?&a)
))
# No carrying, match pairs of digits and their sums
# My goodness it's beautiful
(?=\d(\S*\ [-+]?(?:0\B)*\3\16)\d(\S*\ [-+]?(?:0\B)*\5\18))
(?=
1\g{-2}(?:1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9|9\g{-1}0)
|2\g{-2}(?:1\g{-1}3|2\g{-1}4|3\g{-1}5|4\g{-1}6|5\g{-1}7|6\g{-1}8|7\g{-1}9|8\g{-1}0|9\g{-1}1)
|3\g{-2}(?:1\g{-1}4|2\g{-1}5|3\g{-1}6|4\g{-1}7|5\g{-1}8|6\g{-1}9|7\g{-1}0|8\g{-1}1|9\g{-1}2)
|4\g{-2}(?:1\g{-1}5|2\g{-1}6|3\g{-1}7|4\g{-1}8|5\g{-1}9|6\g{-1}0|7\g{-1}1|8\g{-1}2|9\g{-1}3)
|5\g{-2}(?:1\g{-1}6|2\g{-1}7|3\g{-1}8|4\g{-1}9|5\g{-1}0|6\g{-1}1|7\g{-1}2|8\g{-1}3|9\g{-1}4)
|6\g{-2}(?:1\g{-1}7|2\g{-1}8|3\g{-1}9|4\g{-1}0|5\g{-1}1|6\g{-1}2|7\g{-1}3|8\g{-1}4|9\g{-1}5)
|7\g{-2}(?:1\g{-1}8|2\g{-1}9|3\g{-1}0|4\g{-1}1|5\g{-1}2|6\g{-1}3|7\g{-1}4|8\g{-1}5|9\g{-1}6)
|8\g{-2}(?:1\g{-1}9|2\g{-1}0|3\g{-1}1|4\g{-1}2|5\g{-1}3|6\g{-1}4|7\g{-1}5|8\g{-1}6|9\g{-1}7)
|9\g{-2}(?:1\g{-1}0|2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8)
|0\g{-2}(\d)\g{-2}\g{-1}
|(\d)\g{-4}0\g{-3}\g{-1}
)
|
# Carrying, match pairs of digits and their sums + 1
(?=\d((?-5))\d((?-5)))
(?=
1\g{-2}(?:0\g{-1}2|1\g{-1}3|2\g{-1}4|3\g{-1}5|4\g{-1}6|5\g{-1}7|6\g{-1}8|7\g{-1}9|8\g{-1}0|9\g{-1}1)
|2\g{-2}(?:0\g{-1}3|1\g{-1}4|2\g{-1}5|3\g{-1}6|4\g{-1}7|5\g{-1}8|6\g{-1}9|7\g{-1}0|8\g{-1}1|9\g{-1}2)
|3\g{-2}(?:0\g{-1}4|1\g{-1}5|2\g{-1}6|3\g{-1}7|4\g{-1}8|5\g{-1}9|6\g{-1}0|7\g{-1}1|8\g{-1}2|9\g{-1}3)
|4\g{-2}(?:0\g{-1}5|1\g{-1}6|2\g{-1}7|3\g{-1}8|4\g{-1}9|5\g{-1}0|6\g{-1}1|7\g{-1}2|8\g{-1}3|9\g{-1}4)
|5\g{-2}(?:0\g{-1}6|1\g{-1}7|2\g{-1}8|3\g{-1}9|4\g{-1}0|5\g{-1}1|6\g{-1}2|7\g{-1}3|8\g{-1}4|9\g{-1}5)
|6\g{-2}(?:0\g{-1}7|1\g{-1}8|2\g{-1}9|3\g{-1}0|4\g{-1}1|5\g{-1}2|6\g{-1}3|7\g{-1}4|8\g{-1}5|9\g{-1}6)
|7\g{-2}(?:0\g{-1}8|1\g{-1}9|2\g{-1}0|3\g{-1}1|4\g{-1}2|5\g{-1}3|6\g{-1}4|7\g{-1}5|8\g{-1}6|9\g{-1}7)
|8\g{-2}(?:0\g{-1}9|1\g{-1}0|2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8)
|9\g{-2}(?:0\g{-1}0|1\g{-1}1|2\g{-1}2|3\g{-1}3|4\g{-1}4|5\g{-1}5|6\g{-1}6|7\g{-1}7|8\g{-1}8|9\g{-1}9)
|0\g{-2}(?:0\g{-1}1|1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9|9\g{-1}0)
)
)
\d
)++
# Paths to success
(?:
# A, B and C contain no more significant digits
(?:\.0+)?0*\ [-+]?0*\3\15(?:\.0+)?0*\ [-+]?0*\5\17(?:\.0+)?0*$
|
# A contains no more significant digits, match B's excess to C's
\ [-+]?0*\3\15(\.?\d*?)0*\ [-+]?0*\5\17\g{-1}(?:\.0+)?0*$
|
# B contains no more significant digits, match A's excess to C's
(\.?\d*?)0*\ [-+]?0*\3\15\ [-+]?0*\5\17\g{-1}(?:\.0+)?0*$
|
# C contains no more significant digits but A and B both do
# Match pairs of digits that total 9 until one that totals 10 is found
\.?
(?:
(?=\d\d((?&b))((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d
(?=\S*?(\g{-5}(\g{-5})))
)*+
# Match a pair that totals 10 then validate
(?=\d(\g{-3}|(?&b)\.?))
(?=1\g{-1}9|2\g{-1}8|3\g{-1}7|4\g{-1}6|5\g{-1}5|6\g{-1}4|7\g{-1}3|8\g{-1}2|9\g{-1}1)
\d0*\ [-+]?0*\3\15\g{-2}?+\.?\d0*\ [-+]?0*\5\17\.?0*$
)
|
# Case 2: handle "-A B C" and "A -B -C", ie. check A+C=B
(?=-(?!.*-)|[^-]\S*\ -\S*\ -)
[-+]?(?:0\B)*+
# Check leading excess digits
(?=
(?(?!\1\.?(?!(?!(?&c))))
# No carrying, match one excess part to the other
(?=\S+\ [-+]?0*\1\5\4\b)
|
# Carrying, match one excess part to 1 + the other
# There are two paths here depending on whether |A| < |C| or |C| <= |A|
(?|
# |A| < |C|
(?!.++\5)
\S+\ [-+]?(?:0\B)*+(?=\S*(\ [-+]?(?:0\B)*+)())
# Check for carrying with all '9's
(?(?=\S*\41[9]*\6\b)
# If so, match '9's to '0's and check for a leading '1'
1(?:0(?=\S*\41(\g{-1}?+9)))*?
\4\b\S*\41\g{-1}?+\6\b
|
# Otherwise, match equivalent pairs of digits until they differ by 1
# Then pair any extra '0's with '9's
(?:(\d)(?=\S*\41(\g{-1}?+\g{-2})))*+
(?=\d(\S*\41\g{-2}?+))(?=1\g{-1}0|2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8)
\d
(?:0(?=\S*\41\g{-2}?+\d(\g{-1}?+9)))*?
\4\b\S*\41\g{-3}?+\d\g{-1}?+\6\b
)
|
# |C| <= |A|, basically the same comments as above
(?=.*+\5)
(?=\d*?(\2)\b(\S*\ [-+]?(?:0\B)*+))
(?(?=9*\41\b)
(?:9(?=\d*?\42[1](\g{-1}?+0)))*?
\41\42[1]\g{-1}?+\4\b
|
(?:(\d)(?=\d*\42(\g{-1}?+\g{-2})))*+
(?=\d(\d*\42\g{-2}?+))
(?=0\g{-1}1|1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9)
\d
(?:9(?=\S*\42\g{-2}?+\d(\g{-1}?+0)))*?
\41\42\g{-3}?+\d\g{-1}?+\4\b
)
)
)
)
\1
# Check rest of digits
(?:
# Identify next group of digits to examine
(?=\.?(\d)\S*\ [-+]?(?:0\B)*+\3((\g{-2}?+\.?)\d)\S*\ [-+]?(?:0\B)*+\5((\g{-2}?+\.?)\d))
\.?(*SKIP)
# Check for carrying and match digits accordingly
(?(?=(?!
\48\.?
(?<c>
# Match pairs of digits that totals 9
(?:
(?=\d\.?\d(?<d>\S*?\ \S+\ [-+]?(?:0\B)*\5\51?+)((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d\.?(?=\S*?(\g{-5}\g{-4}))
)*+
# Match a pair of digits that totals > 9
(?=\d(\g{-2}\.?|(?&d)\.?))
(?=[5-9]\g{-1}[5-9]|1\g{-1}9|2\g{-1}[89]|3\g{-1}[7-9]|4\g{-1}[6-9]|6\g{-1}4|7\g{-1}[34]|8\g{-1}[2-4]|9\g{-1}[1-4])
){0}
# Backreferences were erroneously being set that carried over to subsequent iterations,
# necessitating this silly subroutine call
(?&c)
))
# No carrying, match pairs of digits and their sums
(?=\d(\S*\ [-+]?(?:0\B)*\3\50)\d(\S*\ [-+]?(?:0\B)*\5\52))
(?=
1\g{-2}(?:2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8|0\g{-1}9)
|2\g{-2}(?:3\g{-1}1|4\g{-1}2|5\g{-1}3|6\g{-1}4|7\g{-1}5|8\g{-1}6|9\g{-1}7|0\g{-1}8|1\g{-1}9)
|3\g{-2}(?:4\g{-1}1|5\g{-1}2|6\g{-1}3|7\g{-1}4|8\g{-1}5|9\g{-1}6|0\g{-1}7|1\g{-1}8|2\g{-1}9)
|4\g{-2}(?:5\g{-1}1|6\g{-1}2|7\g{-1}3|8\g{-1}4|9\g{-1}5|0\g{-1}6|1\g{-1}7|2\g{-1}8|3\g{-1}9)
|5\g{-2}(?:6\g{-1}1|7\g{-1}2|8\g{-1}3|9\g{-1}4|0\g{-1}5|1\g{-1}6|2\g{-1}7|3\g{-1}8|4\g{-1}9)
|6\g{-2}(?:7\g{-1}1|8\g{-1}2|9\g{-1}3|0\g{-1}4|1\g{-1}5|2\g{-1}6|3\g{-1}7|4\g{-1}8|5\g{-1}9)
|7\g{-2}(?:8\g{-1}1|9\g{-1}2|0\g{-1}3|1\g{-1}4|2\g{-1}5|3\g{-1}6|4\g{-1}7|5\g{-1}8|6\g{-1}9)
|8\g{-2}(?:9\g{-1}1|0\g{-1}2|1\g{-1}3|2\g{-1}4|3\g{-1}5|4\g{-1}6|5\g{-1}7|6\g{-1}8|7\g{-1}9)
|9\g{-2}(?:0\g{-1}1|1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9)
|0\g{-2}(\d)\g{-2}\g{-1}
|(\d)\g{-4}\g{-1}\g{-3}0
)
|
# Carrying, match pairs of digits and their sums + 1
(?=\d((?-5))\d((?-5)))
(?=
1\g{-2}(?:2\g{-1}0|3\g{-1}1|4\g{-1}2|5\g{-1}3|6\g{-1}4|7\g{-1}5|8\g{-1}6|9\g{-1}7|0\g{-1}8|1\g{-1}9)
|2\g{-2}(?:3\g{-1}0|4\g{-1}1|5\g{-1}2|6\g{-1}3|7\g{-1}4|8\g{-1}5|9\g{-1}6|0\g{-1}7|1\g{-1}8|2\g{-1}9)
|3\g{-2}(?:4\g{-1}0|5\g{-1}1|6\g{-1}2|7\g{-1}3|8\g{-1}4|9\g{-1}5|0\g{-1}6|1\g{-1}7|2\g{-1}8|3\g{-1}9)
|4\g{-2}(?:5\g{-1}0|6\g{-1}1|7\g{-1}2|8\g{-1}3|9\g{-1}4|0\g{-1}5|1\g{-1}6|2\g{-1}7|3\g{-1}8|4\g{-1}9)
|5\g{-2}(?:6\g{-1}0|7\g{-1}1|8\g{-1}2|9\g{-1}3|0\g{-1}4|1\g{-1}5|2\g{-1}6|3\g{-1}7|4\g{-1}8|5\g{-1}9)
|6\g{-2}(?:7\g{-1}0|8\g{-1}1|9\g{-1}2|0\g{-1}3|1\g{-1}4|2\g{-1}5|3\g{-1}6|4\g{-1}7|5\g{-1}8|6\g{-1}9)
|7\g{-2}(?:8\g{-1}0|9\g{-1}1|0\g{-1}2|1\g{-1}3|2\g{-1}4|3\g{-1}5|4\g{-1}6|5\g{-1}7|6\g{-1}8|7\g{-1}9)
|8\g{-2}(?:9\g{-1}0|0\g{-1}1|1\g{-1}2|2\g{-1}3|3\g{-1}4|4\g{-1}5|5\g{-1}6|6\g{-1}7|7\g{-1}8|8\g{-1}9)
|9\g{-2}(?:0\g{-1}0|1\g{-1}1|2\g{-1}2|3\g{-1}3|4\g{-1}4|5\g{-1}5|6\g{-1}6|7\g{-1}7|8\g{-1}8|9\g{-1}9)
|0\g{-2}(?:1\g{-1}0|2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8|0\g{-1}9)
)
)
\d
)++
# Paths to success
(?:
# A, B, and C contain no more significant digits
(?:\.0+)?0*\ [-+]?0*\3\49(?:\.0+)?0*\ [-+]?0*\5\51(?:\.0+)?0*$
|
# A contains no more significant digits, match B's excess to C's
\ [-+]?0*\3\49(\.?\d*?)0*\ [-+]?0*\5\51\g{-1}(?:\.0+)?0*$
|
# C contains no more significant digits, match A's excess to B's
(\.?\d*?)0*\ [-+]?0*\3\49\g{-1}(?:\.0+)?0*\ [-+]?0*\5\51$
|
# B contains no more significant digits but A and B both do
# Match pairs of digits that totals 9 until one that totals 10 is found
\.?
(?:
(?=\d\d((?&d))((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d
(?=\S*?(\g{-5}(\g{-5})))
)*+
# Match a pair that totals 10 then validate
(?=\d(\g{-3}|(?&d)\.?))
(?=1\g{-1}9|2\g{-1}8|3\g{-1}7|4\g{-1}6|5\g{-1}5|6\g{-1}4|7\g{-1}3|8\g{-1}2|9\g{-1}1)
\d0*\ [-+]?0*\3\49\.?0*\ [-+]?0*\5\51\g{-2}?+\.?\d0*$
)
|
# And finally, handle "A -B C" and "-A B -C", ie. check B+C=A
(?=[^-]\S*\ -\S*\ [^-]\S*|-\S*\ [^-]\S*\ -)
[-+]?(?:0\B)*+
# Check leading excess digits
(?=
(?(?!\S+\ [-+]?(?:0\B)*+\3\.?(?!(?!(?&e))))
# No carrying, match one excess part to the other
(?=\3\5\2\b)
|
# Carrying, match one excess part to 1 + the other
(?=\d*(\S*\ (?(?=.*+\3)\S+\ )[-+]?(?:0\B)*+)\d*?(\4|\6)\b)
# Check for carrying with a leading '1' and all '0's
(?(?=10*\2\b)
# If so, match '0's to '9's
1(?:0(?=\d*\75(\g{-1}?+9)))*?
\2\b\75\g{-1}?+\76\b
|
# Otherwise, match equivalent pairs of digits until they differ by 1
# Then pair any extra '0's with '9's
(?:(\d)(?=\d*\75(\g{-1}?+\g{-2})))*+
(?=\d(\d*\75\g{-2}?+))
(?=1\g{-1}0|2\g{-1}1|3\g{-1}2|4\g{-1}3|5\g{-1}4|6\g{-1}5|7\g{-1}6|8\g{-1}7|9\g{-1}8)
\d
(?:0(?=\d*\75\g{-2}?+\d(\g{-1}?+9)))*?
\2\b\75\g{-3}?+\d\g{-1}?+\76\b
)
)
)
\1
# Check rest of digits
(?:
# Identify next group of digits to examine
(?=\.?(\d)\S*\ [-+]?(?:0\B)*+\3((\g{-2}?+\.?)\d)\S*\ [-+]?(?:0\B)*+\5((\g{-2}?+\.?)\d))
\.?(*SKIP)
# Check for carrying and match digits accordingly
(?(?=(?!
\S*\ [-+]?(?:0\B)*+\3\83\.?
(?<e>
# Match pairs of digits that totals 9
(?:
(?=\d\.?\d(?<f>\S*?\ [-+]?(?:0\B)*\5\85?+)((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d\.?
(?=\S*?(\g{-5}\g{-4}))
)*+
# Match a pair of digits that totals > 9
(?=\d(\g{-2}\.?|(?&f)\.?))
(?=[5-9]\g{-1}[5-9]|1\g{-1}9|2\g{-1}[89]|3\g{-1}[7-9]|4\g{-1}[6-9]|6\g{-1}4|7\g{-1}[34]|8\g{-1}[2-4]|9\g{-1}[1-4])
){0}
# Backreferences were erroneously being set that carried over to subsequent iterations,
# necessitating this preposterous subroutine call
(?&e)
))
# No carrying, match pairs of digits and their sums
(?=\d(\S*\ [-+]?(?:0\B)*\3\84)\d(\S*\ [-+]?(?:0\B)*\5\86))
(?=
(?:2\g{-2}1|3\g{-2}2|4\g{-2}3|5\g{-2}4|6\g{-2}5|7\g{-2}6|8\g{-2}7|9\g{-2}8|0\g{-2}9)\g{-1}1
|(?:3\g{-2}1|4\g{-2}2|5\g{-2}3|6\g{-2}4|7\g{-2}5|8\g{-2}6|9\g{-2}7|0\g{-2}8|1\g{-2}9)\g{-1}2
|(?:4\g{-2}1|5\g{-2}2|6\g{-2}3|7\g{-2}4|8\g{-2}5|9\g{-2}6|0\g{-2}7|1\g{-2}8|2\g{-2}9)\g{-1}3
|(?:5\g{-2}1|6\g{-2}2|7\g{-2}3|8\g{-2}4|9\g{-2}5|0\g{-2}6|1\g{-2}7|2\g{-2}8|3\g{-2}9)\g{-1}4
|(?:6\g{-2}1|7\g{-2}2|8\g{-2}3|9\g{-2}4|0\g{-2}5|1\g{-2}6|2\g{-2}7|3\g{-2}8|4\g{-2}9)\g{-1}5
|(?:7\g{-2}1|8\g{-2}2|9\g{-2}3|0\g{-2}4|1\g{-2}5|2\g{-2}6|3\g{-2}7|4\g{-2}8|5\g{-2}9)\g{-1}6
|(?:8\g{-2}1|9\g{-2}2|0\g{-2}3|1\g{-2}4|2\g{-2}5|3\g{-2}6|4\g{-2}7|5\g{-2}8|6\g{-2}9)\g{-1}7
|(?:9\g{-2}1|0\g{-2}2|1\g{-2}3|2\g{-2}4|3\g{-2}5|4\g{-2}6|5\g{-2}7|6\g{-2}8|7\g{-2}9)\g{-1}8
|(?:0\g{-2}1|1\g{-2}2|2\g{-2}3|3\g{-2}4|4\g{-2}5|5\g{-2}6|6\g{-2}7|7\g{-2}8|8\g{-2}9)\g{-1}9
|(\d)\g{-3}0\g{-2}\g{-1}
|(\d)\g{-4}\g{-1}\g{-3}0
)
|
# Carrying, match pairs of digits and their sums + 1
(?=\d((?-5))\d((?-5)))
(?=
(?:2\g{-2}0|3\g{-2}1|4\g{-2}2|5\g{-2}3|6\g{-2}4|7\g{-2}5|8\g{-2}6|9\g{-2}7|0\g{-2}8|1\g{-2}9)\g{-1}1
|(?:3\g{-2}0|4\g{-2}1|5\g{-2}2|6\g{-2}3|7\g{-2}4|8\g{-2}5|9\g{-2}6|0\g{-2}7|1\g{-2}8|2\g{-2}9)\g{-1}2
|(?:4\g{-2}0|5\g{-2}1|6\g{-2}2|7\g{-2}3|8\g{-2}4|9\g{-2}5|0\g{-2}6|1\g{-2}7|2\g{-2}8|3\g{-2}9)\g{-1}3
|(?:5\g{-2}0|6\g{-2}1|7\g{-2}2|8\g{-2}3|9\g{-2}4|0\g{-2}5|1\g{-2}6|2\g{-2}7|3\g{-2}8|4\g{-2}9)\g{-1}4
|(?:6\g{-2}0|7\g{-2}1|8\g{-2}2|9\g{-2}3|0\g{-2}4|1\g{-2}5|2\g{-2}6|3\g{-2}7|4\g{-2}8|5\g{-2}9)\g{-1}5
|(?:7\g{-2}0|8\g{-2}1|9\g{-2}2|0\g{-2}3|1\g{-2}4|2\g{-2}5|3\g{-2}6|4\g{-2}7|5\g{-2}8|6\g{-2}9)\g{-1}6
|(?:8\g{-2}0|9\g{-2}1|0\g{-2}2|1\g{-2}3|2\g{-2}4|3\g{-2}5|4\g{-2}6|5\g{-2}7|6\g{-2}8|7\g{-2}9)\g{-1}7
|(?:9\g{-2}0|0\g{-2}1|1\g{-2}2|2\g{-2}3|3\g{-2}4|4\g{-2}5|5\g{-2}6|6\g{-2}7|7\g{-2}8|8\g{-2}9)\g{-1}8
|(?:0\g{-2}0|1\g{-2}1|2\g{-2}2|3\g{-2}3|4\g{-2}4|5\g{-2}5|6\g{-2}6|7\g{-2}7|8\g{-2}8|9\g{-2}9)\g{-1}9
|(?:1\g{-2}0|2\g{-2}1|3\g{-2}2|4\g{-2}3|5\g{-2}4|6\g{-2}5|7\g{-2}6|8\g{-2}7|9\g{-2}8|0\g{-2}9)\g{-1}0
)
)
\d
)++
# Paths to success
(?:
# A, B, and C contain no more significant digits
(?:\.0+)?0*\ [-+]?0*\3\83(?:\.0+)?0*\ [-+]?0*\5\85(?:\.0+)?0*$
|
# C contains no more significant digits, match A's excess to B's
(\.?\d*?)0*\ [-+]?0*\3\83\g{-1}(?:\.0+)?0*\ [-+]?0*\5\85$
|
# B contains no more significant digits, match A's excess to C's
(\.?\d*?)0*\ [-+]?0*\3\83\ [-+]?0*\5\85\g{-1}(?:\.0+)?0*$
|
# A contains no more significant digits but B and C both do
# Match pairs of digits that total 9 until one that totals 10 is found
\.?0*\ [-+]?(?:0\B)*+\3\83\.?
(?:
(?=\d\d((?&f))((\g{-2}?+\.?)\d))
(?=\d(\S*?\g{-4}\g{-2}))
(?=0\g{-1}9|1\g{-1}8|2\g{-1}7|3\g{-1}6|4\g{-1}5|5\g{-1}4|6\g{-1}3|7\g{-1}2|8\g{-1}1|9\g{-1}0)
\d
(?=\S*?(\g{-5}(\g{-5})))
)*+
# Match a pair that totals 10 then validate
(?=\d(\g{-3}|(?&f)\.?))
(?=1\g{-1}9|2\g{-1}8|3\g{-1}7|4\g{-1}6|5\g{-1}5|6\g{-1}4|7\g{-1}3|8\g{-1}2|9\g{-1}1)
\d0*\ [-+]?0*\5\85\g{-2}?+\.?\d0*$
)
)
I think I need to re-evaluate my life choices.
YOU didn't make that. YOU don't need the reevaluation.
Boy, seeing regex like that makes me feel glad it's not Turing complete. I think one of my Perl books has a regex to parse a properly formed email address.
Boy, seeing regex like that makes me feel glad it's not Turing complete. I think one of my Perl books has a regex to parse a properly formed email address.
It's a page and a half.
Yeah. Any string parsing beyond something that can be done with the basic string.h functions is a nightmare that I avoid as much as possible. Someone tried to get me to write a URL parser and I said (basically) "LOL fuck off mate".
I've put it off for a year+ so far, hoping to stall until we pick up cURL 7.62+.
It's always a fun conversation, especially since the whole point is to keep users from doing something our docs tell them not to do anyway (put password in URL: ftp://user:[email protected]<ip>)
Them: "Just search for the colon and at-sign, ez-pz"
Me: "Colons and at-signs are valid characters in passwords"
Them: "Well then just hide the user-name too."
Me: "No, fuck off"
Them: "But we neeeeed it"
Me: "No, you actually don't. All of our security certification say we just have to not store it, here's the line"
Them: "Oh well, still it would be nice"
Me: "No, fuck off"
What are you optimising for? Most readable, or shortest? If there is no option/pattern match in C#(or other idiomatic way to deal with null values), best you can do is actually your very first line.
Null coalesce is the preferred option in C# usually.
If they know about ternary they know about null coalescing usually.
Null coalescing operator is old enough and has enough cousins in other languages that I feel fine with it. I find null-conditional-member operator a little less readable, and it's a little newer, but it's probably fine.
@zeeny I'm mapping a list of objects to an array of strings to plug into a method I don't control. The full code is:
seems like a missed structural opportunity; eventually your code should be able to ensure that there aren't nulls going around everywhere to avoid madness
the null conditional stuff is nuts when you get deep into it and you've got ? tossed everywhere to avoid nulls
It keeps feeling like an anti-pattern to me, like `return this?.feels?.wrong?[somehow];`, but in moderation it's faster than creating null object pattern classes for the "right" way.
seems like a missed structural opportunity; eventually your code should be able to ensure that there aren't nulls going around everywhere to avoid madness
It sounds to me, good sir, that you are ready for some monads in your life.
seems like a missed structural opportunity; eventually your code should be able to ensure that there aren't nulls going around everywhere to avoid madness
When you deal with human inputted data as like 90% of your data that shit shows up everywhere.
I have to import medical documents from other EHRs that aren't as good at ensuring data integrity as I am. I've gotten medical records where there's no patient name and just internal IDs. Of course my system original had anticipated that never being an issue because I was so innocent back then.
Everything checks for nulls, every time, at every step.
not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
seems like a missed structural opportunity; eventually your code should be able to ensure that there aren't nulls going around everywhere to avoid madness
When you deal with human inputted data as like 90% of your data that shit shows up everywhere.
I have to import medical documents from other EHRs that aren't as good at ensuring data integrity as I am. I've gotten medical records where there's no patient name and just internal IDs. Of course my system original had anticipated that never being an issue because I was so innocent back then.
Everything checks for nulls, every time, at every step.
oh yeah, it's just probably nicer if you handle all that stuff immediately upon receiving the user data so the rest of your code doesn't have to constantly interrogate for existence
IMO it's better to check for nulls. Even if your structure is perfect right now, that doesn't mean it will still be perfect in 5 years when some other dev has 'extended' the system with some sort of kludge.
seems like a missed structural opportunity; eventually your code should be able to ensure that there aren't nulls going around everywhere to avoid madness
I'm working on Unity, and it manages a C# List through a UI, so the contents of the list can, at any time, be null. And not just all of them or at the beginning or end, any item in any position can suddenly be null.
To make a drop-down for a user to select one of those, I have to plug the list into a method that expects an array of strings.
A "missed structural opportunity" is a bit of an understatement when it comes to Unity. But like bowen was saying, you have to check every value at every stage when interacting that closely with data out of your control.
yeah i mean if your framework fucks you then there's little you can do short of abstracting away the framework, which is probably way too much work to do to keep all your internal state nice and non-null
+2
gavindelThe reason all your softwareis brokenRegistered Userregular
Man, it has been too long since I honed the edge of being a software engineer. Day to day work depends far more on the detailed knowledge of my local product development environment, and its so easy to let the CS fundamentals slide away. I'm drawing up a mental map of what I would consider the "fundamentals" for CS. I think it goes something like this:
Mathematics:
Basic algebra
Enough calculus to be applied in other areas
As much linear algebra as I can cram into my brain
Statistics
Set theory
Computer science:
The usual go-to algorithms: sorts, hashes, linked lists.
Computability and algorithm analysis (Big-O analysis, P vs NP)
Basic compiler design - AST, language trade offs, desirable features in a language
All the math above
Software engineering:
Functional programming paradigms
OOP paradigms
SOLID principles
Refactoring and error analysis
Test design -> especially good design in patterns for testability.
Common environments: Standing up and running production environments on Unix vs Windows, for example
Source control
Domain:
Pick a subset of:
Machine learning
Computer security (Algorithms and design)
Computer security (in practice and at scale. Ie, defense in depth, assumed breach.)
Concrete examples of use for everything in the list above
Language of choice mastered to a level of being able to pick out details
(Example: C#. Difference between const and readonly at compile time between two programs with variable cross references)
Broad refresher on at least one functional, one OOP, and one web-focused language enough to do whiteboarding and simple programs
Angels, innovations, and the hubris of tiny things: my book now free on Royal Road! Seraphim
+2
JacobyOHHHHH IT’S A SNAKECreature - SnakeRegistered Userregular
This actually hits at the perfect time, since I'm thinking of changing careers from education to CS/software engineering.
On that note, I have the following: B.Sc (Biochem/Bio double major), B.Ed. (secondary education). Should I just do a B. Comp. Sci, or a Masters? I'm an international teacher right now, so being able to teach and do distance ed would be ideal.
GameCenter: ROldford
Switch: nin.codes/roldford
0
GnomeTankWhat the what?Portland, OregonRegistered Userregular
edited November 2018
So this is my advice. As with all advice on the internet take it with a grain of salt.
I've had two friends transition in to development from completely divergent careers with degrees that don't relate at all to the profession. Neither of them went back to school and paid out the nose to get another degree. They both went to a local, very reputable, coding vocational school and did a high intensity course aimed specifically at people wanting to make a career change. The place we have here locally has an excellent reputation for producing people ready to be junior developers and has excellent post graduation job and intern placement support. It's a very real world curriculum that covers all the things we've been talking about in this thread that CS doesn't cover a lot of the time: Source control, working with a team, working under deadline, working with product owners, groking requirements and building code to spec, writing tests, dealing with some light infrastructure. The culmination of the class is a large project that is basically done in agile teams with an actual deliverable, product owner demos, etc.
If something like that is available in your area I think it's really the best way to go if you're already college educated and already have another job to support yourself. They both did this as basically night and weekend classes and it was super intense over a period of months. They also did a ton of self study even before they started the code school so that they had the basics down. It took commitment from both of them but they are now both junior engineers with full time employment and doing really well for themselves.
The reason I recommend this kind of scenario in your case is that no amount of going and getting a CS degree is going to change the fact that you are going to do some time in the trenches as a junior engineer. As someone who already has a degree you want the shortest path from where you are to your butt in a seat as a junior engineer.
Posts
I don't get it. Is aux a reserved word or something?
https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
"Do not use the following reserved names for the name of a file:
CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. Also avoid these names followed immediately by an extension; for example, NUL.txt is not recommended."
I know Windows is wonky sometimes, but it was in C89, so...
SE++ Forum Battle Archive
assert is definitely part of C99, but I'm not sure if it's part of the standard library before then.
The twitter thread goes into some details, but basically (if I read this correctly) it's due to how the major OS in the 70s treated everything as a file, so things that are services (like the printer port) were prevented from having files that shared that name. DOS inherited that for backwards compatibility and... well, never changed it.
The user here was copying a file from Linux, which doesn't have that "feature" and Windows denied it.
I remember that in windows 95, "copy con: con:" would immediately bluescreen the system. This was the heyday of autorun media so that was an absolute hoot to deal with.
Solution: use a regex!
http://www.drregex.com/2018/11/how-to-match-b-c-where-abc-beast-reborn.html
I think I need to re-evaluate my life choices.
I got 99 problems but an overly complex regex ain't one.
YOU didn't make that. YOU don't need the reevaluation.
A younger me would have totally attempted to make that.
It's a page and a half.
Yeah. Any string parsing beyond something that can be done with the basic string.h functions is a nightmare that I avoid as much as possible. Someone tried to get me to write a URL parser and I said (basically) "LOL fuck off mate".
I've put it off for a year+ so far, hoping to stall until we pick up cURL 7.62+.
I don't see what could go wr-oh wait I do that's what I work with.
It's always a fun conversation, especially since the whole point is to keep users from doing something our docs tell them not to do anyway (put password in URL: ftp://user:[email protected]<ip>)
Them: "Just search for the colon and at-sign, ez-pz"
Me: "Colons and at-signs are valid characters in passwords"
Them: "Well then just hide the user-name too."
Me: "No, fuck off"
Them: "But we neeeeed it"
Me: "No, you actually don't. All of our security certification say we just have to not store it, here's the line"
Them: "Oh well, still it would be nice"
Me: "No, fuck off"
My best rendering is but that seems a little obtuse.
If they know about ternary they know about null coalescing usually.
Null coalescing operator is old enough and has enough cousins in other languages that I feel fine with it. I find null-conditional-member operator a little less readable, and it's a little newer, but it's probably fine.
@zeeny I'm mapping a list of objects to an array of strings to plug into a method I don't control. The full code is:
_techPopupSelectedIndex = EditorGUILayout.Popup( "Current Tech", _techPopupSelectedIndex, Target._techSet.techs.Select((t) => t?.ToString() ?? "Null").ToArray() );It only comes up once, so I figured a lambda would be more context-relevant than writing a method for it.
It keeps feeling like an anti-pattern to me, like `return this?.feels?.wrong?[somehow];`, but in moderation it's faster than creating null object pattern classes for the "right" way.
It sounds to me, good sir, that you are ready for some monads in your life.
When you deal with human inputted data as like 90% of your data that shit shows up everywhere.
I have to import medical documents from other EHRs that aren't as good at ensuring data integrity as I am. I've gotten medical records where there's no patient name and just internal IDs. Of course my system original had anticipated that never being an issue because I was so innocent back then.
Everything checks for nulls, every time, at every step.
oh yeah, it's just probably nicer if you handle all that stuff immediately upon receiving the user data so the rest of your code doesn't have to constantly interrogate for existence
I'm working on Unity, and it manages a C# List through a UI, so the contents of the list can, at any time, be null. And not just all of them or at the beginning or end, any item in any position can suddenly be null.
To make a drop-down for a user to select one of those, I have to plug the list into a method that expects an array of strings.
A "missed structural opportunity" is a bit of an understatement when it comes to Unity. But like bowen was saying, you have to check every value at every stage when interacting that closely with data out of your control.
Mathematics:
Computer science:
Software engineering:
Domain:
Pick a subset of:
Interviewing:
On that note, I have the following: B.Sc (Biochem/Bio double major), B.Ed. (secondary education). Should I just do a B. Comp. Sci, or a Masters? I'm an international teacher right now, so being able to teach and do distance ed would be ideal.
Switch: nin.codes/roldford
I've had two friends transition in to development from completely divergent careers with degrees that don't relate at all to the profession. Neither of them went back to school and paid out the nose to get another degree. They both went to a local, very reputable, coding vocational school and did a high intensity course aimed specifically at people wanting to make a career change. The place we have here locally has an excellent reputation for producing people ready to be junior developers and has excellent post graduation job and intern placement support. It's a very real world curriculum that covers all the things we've been talking about in this thread that CS doesn't cover a lot of the time: Source control, working with a team, working under deadline, working with product owners, groking requirements and building code to spec, writing tests, dealing with some light infrastructure. The culmination of the class is a large project that is basically done in agile teams with an actual deliverable, product owner demos, etc.
If something like that is available in your area I think it's really the best way to go if you're already college educated and already have another job to support yourself. They both did this as basically night and weekend classes and it was super intense over a period of months. They also did a ton of self study even before they started the code school so that they had the basics down. It took commitment from both of them but they are now both junior engineers with full time employment and doing really well for themselves.
The reason I recommend this kind of scenario in your case is that no amount of going and getting a CS degree is going to change the fact that you are going to do some time in the trenches as a junior engineer. As someone who already has a degree you want the shortest path from where you are to your butt in a seat as a junior engineer.