Last active
April 6, 2025 07:37
-
-
Save CHatmaker/cfea5c2804a278ca9b620742e7128b2f to your computer and use it in GitHub Desktop.
When learners are entering formulas in instructional workbooks, RXFormulaPromptλ( Prompt, Formula, Entry), tells the learner what to enter and guides them in correcting errors.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* A collection of 5g Functions for creating classroom exercises that prompt | |
learners during formula entry. Suggested module name: RXF | |
*/ | |
/* FUNCTION NAME: Aboutλ | |
DESCRIPTION:*//**Displays the URL to this module's Gist which includes documentation*/ | |
/* REVISIONS: Date Developer Description | |
Dec 16 2024 Craig Hatmaker Copyright | |
Dec 18 2024 Craig Hatmaker Added IsCommentλ, DisplayλLinesλ, and DisplayλPromptsλ | |
Jan 02 2025 Craig Hatmaker See FormulaSplitλ | |
Jan 05 2025 Craig Hatmaker See DisplayEntriesλ | |
Jan 18 2025 Craig Hatmaker Removed RXF. references | |
Feb 04 2025 Craig Hatmaker Added AreRefsSameλ | |
*/ | |
Aboutλ = | |
LET(Group1, TRIM(TEXTSPLIT( | |
"About: →A collection of 5g Functions for creating classroom exercises that prompt¶" & | |
"→learners during formula entry. Suggested module name: RXF¶" & | |
"Version: →Feb 04 2025¶" & | |
"Gist URL: →https://gist.github.com/CHatmaker/cfea5c2804a278ca9b620742e7128b2f ¶" & | |
"Website: →https://sites.google.com/site/beyondexcel/home/excel-library/ ¶" & | |
"→¶" & | |
"Functions →Description¶" & | |
"Aboutλ →Produces this table¶" & | |
"FormulaPromptλ →Prompt learner to enter formula, check answer, provide feedback¶" & | |
"Promptλ →Prompt learner to enter a non-formula, check answer, provide feedback¶" & | |
"DisplayEntriesλ →Creates a dynamic array of learner entries with comment lines and LET step names¶" & | |
"DisplayPromptsλ →Creates a dynamic array of Formula Prompts with comment lines¶" & | |
"→¶" & | |
"Prompt Support→¶" & | |
"FormulaSplitλ →Split a formula into an array of references, functions, operators, and various bracket types¶" & | |
"RXEscapeSpecCharsλ →Apply escape characters where characters in a string match RegEx special characters¶" & | |
"Formula2RXλ →Convert a formula into a regular expression pattern¶" & | |
"RX2Formulaλ →Revert a RegEx version of a formula to a normal formula¶" & | |
"CreateSolutionsλ →Create a dynamic array of solutions without LAMBDA or LET step names", | |
"→","¶" | |
)), | |
Group2, TRIM(TEXTSPLIT( | |
"'Is' functions→¶" & | |
"IsArrayλ →Is string enclosed in curly brackets¶" & | |
"IsBracketedλ →Is string enclosed in square brackets¶" & | |
"IsCellRefλ →Is string a single cell reference¶" & | |
"IsCommentλ →Is string a LAMBDA comment¶" & | |
"IsFunctionλ →Is string a function¶" & | |
"IsQuotedλ →Is string enclosed in double quotes¶" & | |
"IsRangeRefλ →Is string a range reference¶" & | |
"IsStrucRefλ →Is string a structured reference¶" & | |
"AreRefsSameλ →Determine if two reference strings are the same range¶" & | |
"→¶" & | |
"'Get' functions→¶" & | |
"GetFunctionsλ →Extract functions from a formula¶" & | |
"GetOprsλ →Extract operators from a formula¶" & | |
"→¶" & | |
"Literals →Description - Regular Expressions for finding...¶" & | |
"RegExChars →Characters special inside regular expressions¶" & | |
"Operators →Excel formula operators¶" & | |
"BracketsAndCommas →Parentheses, square brackets, curly brackets, and commas¶" & | |
"FunctionExclude →Characters that formulas cannot contain anywhere¶" & | |
"FunctionExcludeStart →Characters that formulas cannot start with¶" & | |
"Function →Functions in a formula¶" & | |
"SheetRef →The portion of a reference from a different sheet that identifies the sheet¶" & | |
"SingleCellRef →Single cell address (example A1, $A1, A$1, or $A$1) in a formula¶" & | |
"ColumnRef →Column reference (example A:A) in a formula¶" & | |
"RowRef →Row reference (example 1:1) in a formula¶" & | |
"RangeRef →Range reference (example A1:B1, etc.) in a formula¶" & | |
"CellRef →Either of Single cell, column, row, or range references in a formula¶" & | |
"StructuredRef →Structured reference (example Table1[Column]) in a formula¶" & | |
"LAMBDAStart →LAMBDA function start¶" & | |
"LAMBDALETStep →LAMBDA LET step¶" & | |
"LAMBDAComment →LAMBDA comment¶" & | |
"Array →String enclosed in curly brackets¶" & | |
"QuotedString →String enclosed in double quotes", | |
"→","¶" | |
)), | |
Result, VSTACK(Group1, {"",""}, Group2), | |
Result | |
); | |
// Named Literals | |
/** Special characters used as operators in Regular Expressions*/ | |
RegExChars = "[\\\^\$\.\|\?\*\+\(\)\{\}\[\]]"; | |
/** Excel's operators*/ | |
Operators = "(<=|>=|<>|[\+\-\*\/\=\<\>\^\&])"; | |
/** Excel's brackets and separators*/ | |
BracketsAndCommas = "[\[\]\(\)\{\}\,\;]"; | |
//https://www.linkedin.com/feed/update/urn:li:activity:7281414089476579329?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A7281414089476579329%2C7281482277191106560%29&dashCommentUrn=urn%3Ali%3Afsd_comment%3A%287281482277191106560%2Curn%3Ali%3Aactivity%3A7281414089476579329%29 | |
/** RegEx pattern for anything between normal brackets*/ | |
BetweenBrackets = "(?<=\p{Ps}).+?(?=\p{Pe})"; | |
// Functions | |
/** Illegal characters anywhere in function names */ | |
FunctionExclude = "•‼\s!""#$%'\(\)\*\+,-/:;<=>@\[\]\^'{|}~`¢£¥¬«»"; | |
/** Illegal first characters in function names */ | |
FunctionExcludeStart = "☺☻♦◘◙♫☼►◄▬↨.0123456789⌂₧⌐░▐▀⌠⌡∙"; | |
/** RegEx pattern for extracting legal function names from a string */ | |
Function = "[^" & FunctionExcludeStart & FunctionExclude & "]{1}[^" & FunctionExclude & "]*\("; | |
// References | |
/** RegEx pattern for extracting sheet names from Excel cell references */ | |
SheetRef = "('?.*'?!)"; | |
/** RegEx pattern for extracting single cell references from Strings */ | |
SingleCellRef = SheetRef & "?(\$?[A-Za-z]{1,3})(\$?[0-9]{1,7}#?)"; | |
/** RegEx pattern for extracting column references from Strings */ | |
ColumnRef = SheetRef & "?\$?[A-Za-z]{1,3}:\$?[A-Za-z]{1,3}"; | |
/** RegEx pattern for extracting row references from Strings */ | |
RowRef = SheetRef & "?\$?\d{1,7}:\$?\d{1,7}"; | |
/** RegEx pattern for extracting range (multi-cell) references from Strings */ | |
RangeRef = SheetRef & "?(\$?[A-Za-z]{1,3}\$?\d{1,7}#?)(:|.:|.:.|:.)(\$?[A-Za-z]{1,3}\$?\d{1,7}#?)"; | |
/** RegEx pattern for extracting cell addresses of anytype from Strings */ | |
CellRef = SheetRef & "?(" & SingleCellRef & "|" & ColumnRef & "|" & RowRef & "|" & RangeRef & ")"; | |
/** RegEx pattern for extracting Structured References from Strings */ | |
StructuredRef = "([A-Za-z_\\][A-Za-z0-9._]*(\[{1,2}(\#ALL|\#Headers|\#Data|\#Totals|\#This Row)\] \,)?)?(((\[{1,2}@\[)|(\[@)|\[{1,2})([^\[])+\])(:(\[)([^\[])+\])?"; | |
// LAMBDA sections | |
/** RegEx pattern for extracting LAMBDA start from formulas */ | |
LAMBDAStart = "^\w=LAMBDA\(.*"; | |
/** RegEx pattern for extracting LET steps from formulas */ | |
LAMBDALETStep = "^\w\,.*"; | |
/** RegEx pattern for extracting comments from LAMBDAs. Does not handle comment lines between frist and last comment line */ | |
LAMBDAComment = "(//|/\*|/\*\*).*"; | |
// Groupings | |
/** RegEx pattern for identifying arrays in formulas */ | |
Array = "{.*?}"; | |
/** RegEx pattern for identifying quoted values in formulas */ | |
QuotedString = """(.*?)"""; | |
/* FUNCTION NAME: FormulaPromptλ | |
DESCRIPTION:*//**Prompt learner to enter formula, check answer, provide feedback*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
FormulaPromptλ = LAMBDA( | |
// Parameter Declarations | |
[Prompt], | |
[Formula], | |
[Entry], | |
[Concise], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →FormulaPromptλ( Prompt, Formula, Entry, [Concise])¶" & | |
"DESCRIPTION: →Prompt learner to enter formula, check answer, provide feedback¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 06 2024¶" & | |
"PARAMETERS: →¶" & | |
"Prompt →(Required) Tells learner what they should do.¶" & | |
"Formula →(Required) Formula that learner must produce.¶" & | |
"Entry →(Required) Cell in which the learner types their answer.¶" & | |
"Concise →(Optional) Default is FALSE. TRUE=Drop ""? reveals answer""¶" & | |
"EXAMPLES: →Formula¶" & | |
"→=FormulaPromptλ( ""Create a row of numbers from 1 to 10"",¶" & | |
"→=""SEQUENCE( , 10)"", Sheet1!$C$2)", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, OR( ISOMITTED( Prompt), | |
ISOMITTED( Formula) | |
), | |
// Set Defaults | |
Concise, IF( ISOMITTED( Concise), FALSE, Concise), | |
Entry, IF( ISFORMULA( Entry), FORMULATEXT( Entry), Entry), | |
Formula, RegExReplace( Formula, "[\r\n]", ""), | |
// Procedure | |
Result, | |
SWITCH( Entry, | |
0, Prompt & IF( Concise, "", " ""?"" reveals answer"), | |
"?", Formula, | |
Let( | |
Split, IFERROR(FormulaSplitλ(Formula), Formula), | |
RXArray, MAP( Split, RXEscapeSpecCharsλ), | |
Count, COUNTA( RXArray), | |
Counter, SEQUENCE( Count), | |
Response, REDUCE("^", Counter, | |
LAMBDA( Acc, n, | |
IF( LEFT(Acc, 1) = "!", | |
Acc, | |
LET( | |
FormulaElement, INDEX(RXArray, n), | |
FormulaStub, Acc & FormulaElement , | |
ErrorFound?, NOT( RegExTest( Entry, FormulaStub & IF( n = Count, "$",""), 1)), | |
IsFunction, IsFunctionλ(FormulaElement), | |
ErrMessage, IF( ErrorFound?, | |
SWITCH( n, | |
1, IF( XOR(LEFT( Formula, 1) = "=", Left(Entry, 1) = "="), | |
IF( Left(Entry, 1) = "=", | |
"! Do not begin with equal sign", | |
"! Begin with an equals sign." | |
), | |
"! Start with " & RX2Formulaλ( FormulaStub) | |
), | |
Count, IF( XOR(RIGHT( Formula, 1) = ",", Right(Entry, 1) = ","), | |
IF( Right(Entry, 1) = ",", | |
"! Do not end with a comma", | |
"! End with a comma." | |
), | |
"! End with " & RX2Formulaλ( FormulaStub) | |
), | |
SWITCH( FormulaElement, | |
",\s*", "! Add a comma after: " & RX2Formulaλ( Acc), | |
"\)\s*", "! Close the formula with "")"" after: " & RX2Formulaλ( Acc), | |
"! Type " & IF( IsFunction, "Function", "") & ": " & RX2Formulaλ( FormulaElement) & " after:" & RX2Formulaλ( Acc) | |
) | |
), | |
FormulaStub | |
), | |
ErrMessage | |
) | |
) | |
) | |
), | |
IF( LEFT( Response, 1) = "!", Response, "Correct!") | |
) | |
), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: Promptλ | |
DESCRIPTION:*//**Prompt learner to enter a non-formula, check answer, provide feedback*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
Promptλ = LAMBDA( | |
// Parameter Declarations | |
[Prompt], | |
[Solution], | |
[Entry], | |
[Concise], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →Promptλ( Prompt, Formula, Entry, [Concise])¶" & | |
"DESCRIPTION: →Prompt learner to enter a non-formula, check answer, provide feedback¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 07 2024¶" & | |
"PARAMETERS: →¶" & | |
"Prompt →(Required) Tells learner what they should do.¶" & | |
"Solution →(Required) What learner must produce.¶" & | |
"Entry →(Required) Cell in which the learner types their answer.¶" & | |
"Concise →(Optional) TRUE=Drop ""? reveals answer"". Default is FALSE¶" & | |
"EXAMPLES: →Formula¶" & | |
"→=Promptλ( ""Close LET() function"","")"", Sheet1!$C$2))", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, OR( ISOMITTED( Prompt), | |
ISOMITTED( Solution) | |
), | |
// Set Defaults | |
Concise, IF( ISOMITTED( Concise), FALSE, Concise), | |
Answer, Trim(RegExReplace( Solution, "[\r\n]", "")), | |
// Procedure | |
Result, SWITCH( Entry, | |
0, Prompt & IF( Concise, "", " ""?"" reveals answer"), | |
"?", Solution, | |
Solution, "Correct!", | |
"Enter " & Solution | |
), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: DisplayEntriesλ | |
DESCRIPTION:*//**Creates a dynamic array of learner entries with comment lines and LET step names*/ | |
/* REVISIONS: Date Developer Description | |
Dec 18 2024 Craig Hatmaker Copyright | |
Jan 04 2024 Craig Hatmaker Removed leading spaces from names | |
*/ | |
DisplayEntriesλ = LAMBDA([Entries], [Prompts], [Solutions],[IndentSize], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →DisplayEntriesλ( Entries, Prompts, Prefixes, Solutions, [IndentSize])¶" & | |
"DESCRIPTION: →Creates a dynamic array of learner entries with comment lines and LET step names¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 14 2024¶" & | |
"PARAMETERS: →¶" & | |
"Entries →(Required) The first cell where formula entries are made.¶" & | |
"Prompts →(Required) An array of LAMBDA formula Prompts¶" & | |
"Solutions →(Required) An array of entry solutions¶" & | |
"IndentSize →(Optional) Nunmber of spaces to indent. Default is 4¶" & | |
"EXAMPLES: →", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, OR( ISOMITTED( Entries), | |
ISOMITTED( Prompts), | |
ISOMITTED( Solutions) | |
), | |
IndentSize, IF( ISOMITTED(IndentSize), 4, IndentSize), | |
Entries, OFFSET(TAKE(Entries, 1, 1), 0, 0, ROWS( Prompts), 1), | |
// Procedure | |
Levels, SCAN( 0, Solutions, | |
LAMBDA( Acc, VAL, | |
Acc + | |
(LEN(Val) - LEN((SUBSTITUTE(Val,"(","")))) - | |
(LEN(Val) - LEN((SUBSTITUTE(Val,")","")))) | |
) | |
), | |
Names, MAP( Levels, REGEXREPLACE( Solutions, "^\s*", ""), | |
LAMBDA( Lvl, Sol, | |
IF( AND( LvL = 1, REGEXTEST(Sol, ".*=\s*LAMBDA")), | |
TRIM( TEXTBEFORE( Sol, "=")), | |
IF( AND( LVL > 1, REGEXTEST( Sol, "^.*\,.*"), LEFT( Sol, 1) <> "/"), | |
TEXTBEFORE( Sol, ",") & ",", | |
"" | |
) | |
) | |
) | |
), | |
Solutions, MAP( Names, Solutions, LAMBDA( Name, Sol, TEXTAFTER( Sol , Name))), | |
Indents, DROP( VSTACK( 0, Levels), -1), | |
Result, MAP( Entries, Prompts, Names, Solutions, Indents, | |
LAMBDA( Entry, Prompt, Names, Solution, Indent, | |
REPT( " ", MAX(0, (Indent - IsCommentλ(Solution)) * IndentSize)) & | |
IF( Prompt = "", | |
Solution, | |
IF(Entry = "", | |
"", | |
IF( Names = "", | |
TEXT(Entry, "#"), | |
TRIM(Names) & " " & Entry | |
) | |
) | |
) | |
) | |
), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: CreateSolutionsλ | |
DESCRIPTION:*//**Create a dynamic array of solutions without LAMBDA or LET step names*/ | |
/* REVISIONS: Date Developer Description | |
Dec 18 2024 Craig Hatmaker Copyright | |
*/ | |
CreateSolutionsλ = LAMBDA([Solutions], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →CreateSolutionsλ( Solutions)¶" & | |
"DESCRIPTION: →Create a dynamic array of solutions without LAMBDA or LET step names¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 14 2024¶" & | |
"PARAMETERS: →¶" & | |
"Solutions →(Required) An array of entry solutions. Usually LAMBDA text¶" & | |
"EXAMPLES: →", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( Solutions), | |
// Procedure | |
Levels, SCAN( 0, Solutions, | |
LAMBDA( Acc, VAL, | |
Acc + | |
IF( IsCommentλ(Val), | |
0, | |
(LEN(Val) - LEN((SUBSTITUTE(Val,"(","")))) - | |
(LEN(Val) - LEN((SUBSTITUTE(Val,")","")))) | |
) | |
) | |
), | |
Names, MAP( Levels, Solutions, | |
LAMBDA( Lvl, Sol, | |
IF( AND( LvL = 1, REGEXTEST(Sol, ".*=\s*LAMBDA")), | |
TRIM( TEXTBEFORE( Sol, "=")), | |
IF( AND( LVL > 1, REGEXTEST( Sol, "^.*\,.*"), LEFT( Sol, 1) <> "/"), | |
TEXTBEFORE( Sol, ",") & ",", | |
"" | |
) | |
) | |
) | |
), | |
Solutions, MAP( Names, Solutions, | |
LAMBDA( Name, Sol, | |
TRIM(TEXTAFTER( Sol & " ", Name)) | |
) | |
), | |
Result, Solutions, | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: DisplayPromptsλ | |
DESCRIPTION:*//**Creates a dynamic array of formula prompts with comment lines*/ | |
/* REVISIONS: Date Developer Description | |
Dec 18 2024 Craig Hatmaker Copyright | |
*/ | |
DisplayPromptsλ = LAMBDA([Prompts], [Solutions], [Entries], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →DisplayPromptsλ( Prompts, Solutions, Entries)¶" & | |
"DESCRIPTION: →Creates a dynamic array of formula prompts with comment lines¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 14 2024¶" & | |
"PARAMETERS: →¶" & | |
"Prompts →(Required) An array of formula entry prompts when entry is empty¶" & | |
"Solutions →(Required) An array of target formulas¶" & | |
"Entries →(Required) The first cell where entries are made¶" & | |
"EXAMPLES: →", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, OR( ISOMITTED( Prompts), | |
ISOMITTED( Solutions), | |
ISOMITTED( Entries) | |
), | |
Entries, OFFSET(TAKE(Entries, 1, 1), 0, 0, ROWS( Prompts), 1), | |
Solutions, CreateSolutionsλ( Solutions), | |
// Procedure | |
Result, MAP( Prompts, Solutions, Entries, | |
LAMBDA( Prompt, Solution, Entry, | |
IF( Solution = "", | |
Prompt, | |
IF( Prompt= "", | |
"", | |
FormulaPromptλ( Prompt, Solution, Entry, TRUE) | |
) | |
) | |
) | |
), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
// Prompt Support routines | |
/* FUNCTION NAME: FormulaSplitλ | |
DESCRIPTION:*//**Split a formula into an array of references, functions, operators, and various bracket types*/ | |
/* REVISIONS: Date Developer Description | |
Dec 19 2024 Craig Hatmaker Copyright | |
*/ | |
FormulaSplitλ = LAMBDA( | |
// Parameter Declarations | |
[Formula], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →FormulaSplitλ( Formula)¶" & | |
"DESCRIPTION: →Split a formula into an array of references, functions, ¶" & | |
"→operators, and various bracket types¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 19 2024¶" & | |
"PARAMETERS: →¶" & | |
"Formula →(Required) Formula to split into an array¶" & | |
"EXAMPLES: →Formula¶" & | |
"Formula →FormulaSplitλ(""=SCAN(0,$D$81#, SUM)""))¶" & | |
"Result →{=,SCAN(,0,"","",$D$81#,"","",SUM}", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( Formula), | |
// Procedure | |
RXArray, REGEXEXTRACT( Formula, "(" & | |
QuotedString & "|" & Function & "|" & Operators & "|" & | |
CellRef & "|" & BracketsAndCommas & "|" & "[A-Za-z0-9%_.\$#""λ]*" & | |
")",1), | |
Result, FILTER( RXArray, RXArray <> ""), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: RXEscapeSpecCharsλ | |
DESCRIPTION:*//**Apply escape characters where characters in a string match RegEx special characters*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
RXEscapeSpecCharsλ = LAMBDA( | |
// Parameter Declarations | |
[String], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →RXEscapeSpecCharsλ( String)¶" & | |
"DESCRIPTION: →Apply escape characters where characters in a string match¶" & | |
"→RegEx special characters and append /s* to end of string.¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 06 2024¶" & | |
"PARAMETERS: →¶" & | |
"String →(Required) String in which to escape RegEx special characters¶" & | |
"EXAMPLES: →Formula¶" & | |
"Formula →RXEscapeSpecCharsλ(""$D$81"")¶" & | |
"Result →\$D\$81#\s*", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( String), | |
// Procedure | |
IsRangeRef, IsRangeRefλ( String), | |
Escaped, LET(Count, LEN( String), | |
Counter, SEQUENCE( Count), | |
REDUCE( "", Counter, | |
LAMBDA( Acc, n, | |
LET( | |
Char, MID(String, n, 1), | |
IF( RegExTest( Char, RegExChars, 1), | |
Acc & "\" & Char, | |
Acc & Char | |
) | |
) | |
) | |
) | |
), | |
Result, Escaped & "\s*", | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: Formula2RXλ | |
DESCRIPTION:*//**Convert a formula into a regular expression pattern*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
Formula2RXλ = LAMBDA( | |
// Parameter Declarations | |
[Formula], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →Formula2RXλ( Formula)¶" & | |
"DESCRIPTION: →Convert a formula into a regular expression pattern¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 06 2024¶" & | |
"PARAMETERS: →¶" & | |
"Formula →(Required) Formula to convert to a regular expression pattern¶" & | |
"EXAMPLES: →Formula¶" & | |
"Formula →=Formula2RXλ( ""=SEQUENCE( , 10)""),¶" & | |
"Result →^=\s*SEQUENCE\(\s*\,\s*10\s*\)\s*", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( Formula), | |
// Procedure | |
RXArray, MAP(FormulaSplitλ(Formula), RXEscapeSpecCharsλ), | |
Result, CONCAT(RXArray), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: RX2Formulaλ | |
DESCRIPTION:*//**Revert a RegEx version of a formula to a normal formula*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
RX2Formulaλ = LAMBDA( | |
// Parameter Declarations | |
[RegExString], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →RX2Formulaλ( RegExString)¶" & | |
"DESCRIPTION: →Revert a RegEx version of a formula to a normal formula¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 06 2024¶" & | |
"PARAMETERS: →¶" & | |
"RegExString →(Required) RegEx string to revert back to its formula¶" & | |
"EXAMPLES: →Formula¶" & | |
"Formula →RX2Formulaλ(""^=\s*SCAN\(\s*0\s*\,\s*$D$81#\s*\,\s*SUM\s*\)\s*"")¶" & | |
"Result →=SCAN(0,$D$81#,SUM)", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( RegExString), | |
// Procedure | |
ReplaceSpace, RegExReplace( RegExString, "\\s\*", " "), | |
Result, RegExReplace( ReplaceSpace, "\^|\\|\.\*", ""), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
// "Is" Functions | |
/* FUNCTION NAME: IsArrayλ | |
DESCRIPTION:*//**Determine if a string is enclosed in curly brackets*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
IsArrayλ = LAMBDA( | |
[String], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →IsArrayλ( String )¶" & | |
"DESCRIPTION: →Determines if a string is enclosed in curly brackets¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 14 2024¶" & | |
"PARAMETERS: →¶" & | |
"String →(Required) String to test.¶" & | |
"EXAMPLES: →=IsArrayλ({1,2,3})", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( String), | |
// Procedure | |
Result, REGEXTEST( String, "^" & Array & "$", 1), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: IsBracketedλ | |
DESCRIPTION:*//**Determine if a string is enclosed in square brackets*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
IsBracketedλ = LAMBDA( | |
[String], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →IsBracketedλ( String )¶" & | |
"DESCRIPTION: →Determines if a string is enclosed in square brackets¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 14 2024¶" & | |
"PARAMETERS: →¶" & | |
"String →(Required) String to test.¶" & | |
"EXAMPLES: →=IsBracketedλ([This is Bracketed])", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( String), | |
// Procedure | |
Result, REGEXTEST( String, "^\[.*\]$", 1), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: IsCellRefλ | |
DESCRIPTION:*//**Determine if a string is a Range reference*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
IsCellRefλ = LAMBDA(String, | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →IsCellRefλ( String )¶" & | |
"DESCRIPTION: →Determines if a string is a single cell Reference¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 14 2024¶" & | |
"PARAMETERS: →¶" & | |
"String →(Required) String to test.¶" & | |
"EXAMPLES: →=IsCellRefλ(""D10"")", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( String), | |
// Procedure | |
Result, REGEXTEST( String, "^" & SingleCellRef & "$", 1), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: IsCommentλ | |
DESCRIPTION:*//**Determine if a string is a LAMBDA comment*/ | |
/* REVISIONS: Date Developer Description | |
Dec 18 2024 Craig Hatmaker Copyright | |
*/ | |
IsCommentλ = LAMBDA( | |
[String], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →IsCommentλ( String )¶" & | |
"DESCRIPTION: →Determines if a string is a LAMBDA comment¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 14 2024¶" & | |
"PARAMETERS: →¶" & | |
"String →(Required) String to test.¶" & | |
"EXAMPLES: →=IsCommentλ(""//Test"")", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( String), | |
// Procedure | |
Result, REGEXTEST( String, "^" & LAMBDAComment & "$", 1), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: IsFunctionλ | |
DESCRIPTION:*//**Determine if a string is a function*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
IsFunctionλ = LAMBDA( | |
[String], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →IsFunctionλ( String )¶" & | |
"DESCRIPTION: →Determines if a string begins with a function¶" & | |
"→Note! A function MUST have parentheses. Example: SUM().¶" & | |
"→However, we are not concerned about arguments so we only¶" & | |
"→check up to and including the open parenthesis.¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 14 2024¶" & | |
"PARAMETERS: →¶" & | |
"String →(Required) String to test.¶" & | |
"EXAMPLES: →=IsFunctionλ(""STDEV.P()"")", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( String), | |
// Procedure | |
Name, "^" & TEXTBEFORE( String, "(") & "(/s*", | |
Result, IF( ISNA( Name), | |
FALSE, | |
REGEXTEST( Name, Function, 1) | |
), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: IsQuotedλ | |
DESCRIPTION:*//**Determine if a string is enclosed in double quotes*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
IsQuotedλ = LAMBDA( | |
[String], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →IsQuotedλ( String )¶" & | |
"DESCRIPTION: →Determine if a string is enclosed in double quotes¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 14 2024¶" & | |
"PARAMETERS: →¶" & | |
"String →(Required) String to test.¶" & | |
"EXAMPLES: →=IsQuotedλ(""This is quoted"")", | |
"→", "¶" | |
)), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( String), | |
// Procedure | |
Result, REGEXTEST( String, "^" & QuotedString & "$", 1), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: IsRangeRefλ | |
DESCRIPTION:*//**Determine if a string is a Range reference*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
IsRangeRefλ = LAMBDA( | |
[String], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →IsRangeRefλ( String )¶" & | |
"DESCRIPTION: →Determines if a string is a cell/range Reference¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 14 2024¶" & | |
"PARAMETERS: →¶" & | |
"String →(Required) String to test.¶" & | |
"EXAMPLES: →=IsRangeRefλ(""$D1#:D10"")", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( String), | |
// Procedure | |
Result, REGEXTEST( String, "^" & RangeRef & "$", 1), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: IsStrucRefλ | |
DESCRIPTION:*//**Determine if a string is a structured reference*/ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
IsStrucRefλ = LAMBDA( | |
[String], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION: →IsStrucRefλ( String )¶" & | |
"DESCRIPTION: →Determines if a string is as structured Reference¶" & | |
"WEBPAGE: →<coming soon>¶" & | |
"VERSION: →Dec 14 2024¶" & | |
"PARAMETERS: →¶" & | |
"String →(Required) String to test.¶" & | |
"EXAMPLES: →=IsStrucRefλ(""Table1[#All]"")", | |
"→", "¶" ) | |
), | |
// Check inputs - Omitted required arguments | |
Help?, ISOMITTED( String), | |
// Procedure | |
Result, REGEXTEST( String, "^" & StructuredRef & "$", 1), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
/* FUNCTION NAME: AreRefsSameλ | |
DESCRIPTION:*//**Determine if two reference strings are the same range*/ | |
/* REVISIONS: Date Developer Description | |
Feb 04 2025 Craig Hatmaker Copyright | |
*/ | |
AreRefsSameλ = LAMBDA( | |
[Reference1], | |
[Reference2], | |
// Help | |
LET(Help, TRIM(TEXTSPLIT( | |
"FUNCTION →AreRefsSameλ( Reference1, Reference2)¶" & | |
"DESCRIPTION→Determine if two reference strings are the same range¶" & | |
"WEBPAGE →<coming soon>¶" & | |
"VERSION →Feb 04 2025¶" & | |
"PARAMETERS:→¶" & | |
" Reference1→(Required) First range address or name.¶" & | |
" Reference2→(Required) Second range address or name.¶" & | |
"EXAMPLES: →¶" & | |
" Formula →=AreRefsSameλ(""A1:B2"", ""$a$1:$B$2"")¶" & | |
" Result →TRUE", | |
"→", "¶" )), | |
// Check inputs - Omitted required arguments | |
Help?, OR( ISOMITTED( Reference1), | |
ISOMITTED( Reference2) | |
), | |
// Procedure | |
Test, LAMBDA( First, Second, | |
LET( | |
Range1, INDIRECT(First), | |
Range2, INDIRECT(Second), | |
Anchor, CELL("address", Range1) = CELL("address", Range2), | |
Rows, ROWS(Range1) = ROWS(Range2), | |
Cols, COLUMNS(Range1) = COLUMNS(Range2), | |
Result, AND(Anchor, Rows, Cols), | |
Result | |
) | |
), | |
Result, IF( COUNTA( Reference1) = 1, | |
Test( Reference1, Reference2), | |
MAP( Reference1, Reference2, Test) | |
), | |
// Return Result | |
IF( Help?, Help, Result) | |
) | |
); | |
// "Get" functions | |
/* FUNCTION NAME: GetOprsλ | |
DESCRIPTION:*//**Extract Excel operators from a formula string */ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
GetOprsλ = LAMBDA( Formula, RegExExtract(Formula, Operators, 1)); | |
/* FUNCTION NAME: GetFunctionsλ | |
DESCRIPTION:*//**Extract Excel functions from a formula string */ | |
/* REVISIONS: Date Developer Description | |
Dec 06 2024 Craig Hatmaker Copyright | |
*/ | |
GetFunctionsλ = LAMBDA( Formula, RegExExtract(Formula, Function, 1)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment