uCalc API Version: 2.1.3-preview.2 Released: 6/17/2026
Warning
uCalc API Preview Release Notice:The documentation describes the intended behavior of the API. The current preview build contains incomplete features, unoptimized performance, and is subject to breaking changes.
Capturing Text with Variables
Product:
Class:
Explains how to use named placeholders (variables) in patterns to capture, reuse, and validate dynamic text.
Remarks
🎣 Capturing Text with Variables
At the heart of any parsing task is the need to find known text in order to extract unknown text. In uCalc's Transformer, this is done using two simple concepts: Anchors and Variables.
- Anchors are the literal, static text in your pattern that must exist in the source string. They act as guideposts for the parser. In the pattern
User: {name}, the textUser:is the anchor. - Variables are named placeholders enclosed in curly braces
{...}that capture the dynamic, unknown text. InUser: {name}, the variable{name}captures whatever text follows the anchor.
How a Capture Works
By default, a variable like {data} is "smart lazy." It captures all text until it encounters one of three things:
- The next anchor defined in your pattern.
- A statement separator token (like a newline or semicolon).
- The end of the string.
This behavior is incredibly powerful because it automatically respects the natural structure of your text without requiring complex lookaheads or non-greedy specifiers common in Regex.
Using Captured Variables
Once a variable captures text, you can re-insert it in the replacement string using the same {variableName} syntax. This allows you to reformat, wrap, or reorder the extracted data.
var t = new uCalc.Transformer();t.FromTo("Log: {message}", "[LOG] - {message}");Console.WriteLine(t.Transform("Log: System ready."));// Output: [LOG] - System ready.Backreferences: Enforcing Equality
One of the most powerful features is backreferencing. If you use the same variable name multiple times within the pattern string, uCalc enforces that the captured text for each instance must be identical. This is the key to matching balanced structures.
For example, the pattern <{tag}>{content}</{tag}> will correctly match <b>text</b> because the {tag} variable captures b in both places. It will not match <b>text</i>, preventing a common parsing error.
💡 Why uCalc? (Comparative Analysis)
vs. Regular Expressions
Regex uses capture groups (...) and backreferences like $1 or \1. uCalc's approach is superior for several reasons:
- Readability: Named variables like
{user}are far more readable and maintainable than numeric indices like$1. - Token Awareness: A uCalc variable like
{word}automatically respects word boundaries. In Regex, you must manually add boundaries (\bword\b) to prevent partial matches inside other words. - Safe Backreferences: As shown above, matching balanced tags is simple and intuitive in uCalc, while it is often complex and fragile in Regex.
vs. Native String Splitting
Using native functions like string.Split() is common but brittle.
- Positional Fragility:
Split()gives you an array of results that you must access by a numeric index (e.g.,parts[1]). If the input format changes slightly, your indices may be wrong, leading to runtime errors. - Named Access: uCalc variables allow you to access captured data by a meaningful name, making your code more robust and self-documenting.
Examples
Extracts a value from a simple key-value pair.
using uCalcSoftware;
var uc = new uCalc();
var t = new uCalc.Transformer();
t.FromTo("ID: {value}", "Found value: {value}");
Console.WriteLine(t.Transform("Product ID: 12345"));
Product Found value: 12345 using uCalcSoftware; var uc = new uCalc(); var t = new uCalc.Transformer(); t.FromTo("ID: {value}", "Found value: {value}"); Console.WriteLine(t.Transform("Product ID: 12345"));
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
uCalc::Transformer t;
t.FromTo("ID: {value}", "Found value: {value}");
cout << t.Transform("Product ID: 12345") << endl;
}
Product Found value: 12345 #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; uCalc::Transformer t; t.FromTo("ID: {value}", "Found value: {value}"); cout << t.Transform("Product ID: 12345") << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Dim t As New uCalc.Transformer()
t.FromTo("ID: {value}", "Found value: {value}")
Console.WriteLine(t.Transform("Product ID: 12345"))
End Sub
End Module
Product Found value: 12345 Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Dim t As New uCalc.Transformer() t.FromTo("ID: {value}", "Found value: {value}") Console.WriteLine(t.Transform("Product ID: 12345")) End Sub End Module
Parses a structured log entry and reformats it for display using multiple variables.
using uCalcSoftware;
var uc = new uCalc();
var t = new uCalc.Transformer();
// Note the use of {@String} to capture the quoted text
t.FromTo("'['{level}']' Code: {code}, Msg: {@String:message}",
"[{level}] - {message} (Code {code})");
var log = "[ERROR] Code: 404, Msg: 'Not Found'";
Console.WriteLine(t.Transform(log));
[ERROR] - Not Found (Code 404) using uCalcSoftware; var uc = new uCalc(); var t = new uCalc.Transformer(); // Note the use of {@String} to capture the quoted text t.FromTo("'['{level}']' Code: {code}, Msg: {@String:message}", "[{level}] - {message} (Code {code})"); var log = "[ERROR] Code: 404, Msg: 'Not Found'"; Console.WriteLine(t.Transform(log));
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
uCalc::Transformer t;
// Note the use of {@String} to capture the quoted text
t.FromTo("'['{level}']' Code: {code}, Msg: {@String:message}",
"[{level}] - {message} (Code {code})");
auto log = "[ERROR] Code: 404, Msg: 'Not Found'";
cout << t.Transform(log) << endl;
}
[ERROR] - Not Found (Code 404) #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; uCalc::Transformer t; // Note the use of {@String} to capture the quoted text t.FromTo("'['{level}']' Code: {code}, Msg: {@String:message}", "[{level}] - {message} (Code {code})"); auto log = "[ERROR] Code: 404, Msg: 'Not Found'"; cout << t.Transform(log) << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Dim t As New uCalc.Transformer()
'// Note the use of {@String} to capture the quoted text
t.FromTo("'['{level}']' Code: {code}, Msg: {@String:message}",
"[{level}] - {message} (Code {code})")
Dim log = "[ERROR] Code: 404, Msg: 'Not Found'"
Console.WriteLine(t.Transform(log))
End Sub
End Module
[ERROR] - Not Found (Code 404) Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Dim t As New uCalc.Transformer() '// Note the use of {@String} to capture the quoted text t.FromTo("'['{level}']' Code: {code}, Msg: {@String:message}", "[{level}] - {message} (Code {code})") Dim log = "[ERROR] Code: 404, Msg: 'Not Found'" Console.WriteLine(t.Transform(log)) End Sub End Module