uCalc API Version: 2.1.3-preview.2 Released: 6/16/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.
BracketSensitive = [bool]
Property
Product:
Class:
Controls whether a pattern rule respects balanced bracket pairs, preventing matches from crossing structural boundaries like parentheses or braces.
Remarks
🛡️ Structural Integrity: The BracketSensitive Property
The BracketSensitive property controls whether a pattern is aware of nested, balanced bracket pairs. When enabled (the default), it prevents a variable capture from starting inside a bracketed block and ending outside of it, ensuring that structural units like function calls or code blocks are treated atomically.
This is a fundamental feature for safely parsing structured text and a key advantage over traditional regular expressions, which are not context-aware.
⚙️ How It Works
This property acts as a switch for a rule's parsing logic. The behavior can be set per-rule or globally via the Transformer.DefaultRuleSet.
| Setting | Behavior |
|---|---|
true (Default) | Structurally Aware. The parser tracks the nesting depth of brackets. A pattern like A {body} C will not match A (B C) because the closing parenthesis is missing. It correctly matches A (B) C. |
false | Structurally Unaware. Brackets ((), [], {}) are treated like any other generic token. The parser will match across boundaries, which can be useful for certain kinds of text analysis but is generally less safe for structured data. |
By default, uCalc recognizes (), [], and {} as bracket pairs. You can define your own custom pairs (e.g., begin/end or </>) using [uCalc.Tokens.Add](/Reference/uCalcBase/Tokens/Add/Add(string, TokenType, string, int, RegExGrammar, int)).
💡 Why uCalc? (Comparative Analysis)
Regular expressions are notoriously poor at handling nested or recursive structures. A simple regex like \((.*)\) is greedy and will fail to correctly parse nested calls like func(a, sub(b)). While modern regex engines have features like recursive patterns ((?R)), they are complex, difficult to maintain, and can lead to "catastrophic backtracking" performance issues.
uCalc's BracketSensitive property solves this elegantly by leveraging its token-based architecture:
- Tokenizer Awareness: The tokenizer identifies opening and closing brackets first, understanding their relationship.
- Parser State: When
BracketSensitiveistrue, the parser uses this token information to maintain a nesting level counter. - Safe Matching: A pattern variable's capture is only considered complete if the bracket nesting level is the same at the end as it was at the start.
This makes parsing structured, nested data in uCalc both safer and more performant than using regex alone.
Examples
BracketSensitive
using uCalcSoftware;
var uc = new uCalc();
var t = uc.NewTransformer();
var Pattern = t.Pattern("< {etc} >");
t.Str("< a b c > d < (e f g) > h < (i) (j k) > l < m n o ( > p) q >");
// Note the difference in the final match
Pattern.BracketSensitive = true; // true is the default
Console.WriteLine($"BracketSensitive: {Pattern.BracketSensitive}");
Console.WriteLine("----------------------");
t.Find();
Console.WriteLine(t.Matches.Text);
Console.WriteLine("");
Pattern.BracketSensitive = false;
Console.WriteLine($"BracketSensitive: {Pattern.BracketSensitive}");
Console.WriteLine("-----------------------");
t.Find();
Console.WriteLine(t.Matches.Text);
Console.WriteLine("");
t.Str("( a b ( c ) d e )");
// Here parentheses are captured as regular tokens, not bracket pairs
var Pattern2a = t.Pattern("( {etc} (");
var Pattern2b = t.Pattern(") {etc} )");
Console.WriteLine("Brackets used as part of pattern");
Console.WriteLine("--------------------------------");
Pattern2a.BracketSensitive = true;
Pattern2b.BracketSensitive = true;
t.Find();
Console.WriteLine(t.Matches.Text);
Console.WriteLine("");
Pattern2a.BracketSensitive = false;
Pattern2b.BracketSensitive = false;
t.Find();
Console.WriteLine(t.Matches.Text);
BracketSensitive: True
----------------------
< a b c >
< (e f g) >
< (i) (j k) >
< m n o ( > p) q >
BracketSensitive: False
-----------------------
< a b c >
< (e f g) >
< (i) (j k) >
< m n o ( >
Brackets used as part of pattern
--------------------------------
( a b (
) d e )
( a b (
) d e ) using uCalcSoftware; var uc = new uCalc(); var t = uc.NewTransformer(); var Pattern = t.Pattern("< {etc} >"); t.Str("< a b c > d < (e f g) > h < (i) (j k) > l < m n o ( > p) q >"); // Note the difference in the final match Pattern.BracketSensitive = true; // true is the default Console.WriteLine($"BracketSensitive: {Pattern.BracketSensitive}"); Console.WriteLine("----------------------"); t.Find(); Console.WriteLine(t.Matches.Text); Console.WriteLine(""); Pattern.BracketSensitive = false; Console.WriteLine($"BracketSensitive: {Pattern.BracketSensitive}"); Console.WriteLine("-----------------------"); t.Find(); Console.WriteLine(t.Matches.Text); Console.WriteLine(""); t.Str("( a b ( c ) d e )"); // Here parentheses are captured as regular tokens, not bracket pairs var Pattern2a = t.Pattern("( {etc} ("); var Pattern2b = t.Pattern(") {etc} )"); Console.WriteLine("Brackets used as part of pattern"); Console.WriteLine("--------------------------------"); Pattern2a.BracketSensitive = true; Pattern2b.BracketSensitive = true; t.Find(); Console.WriteLine(t.Matches.Text); Console.WriteLine(""); Pattern2a.BracketSensitive = false; Pattern2b.BracketSensitive = false; t.Find(); Console.WriteLine(t.Matches.Text);
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
#define tf(IsTrue) ((IsTrue) ? "True" : "False")
int main() {
uCalc uc;
auto t = uc.NewTransformer();
auto Pattern = t.Pattern("< {etc} >");
t.Str("< a b c > d < (e f g) > h < (i) (j k) > l < m n o ( > p) q >");
// Note the difference in the final match
Pattern.BracketSensitive(true); // true is the default
cout << "BracketSensitive: " << tf(Pattern.BracketSensitive()) << endl;
cout << "----------------------" << endl;
t.Find();
cout << t.Matches().Text() << endl;
cout << "" << endl;
Pattern.BracketSensitive(false);
cout << "BracketSensitive: " << tf(Pattern.BracketSensitive()) << endl;
cout << "-----------------------" << endl;
t.Find();
cout << t.Matches().Text() << endl;
cout << "" << endl;
t.Str("( a b ( c ) d e )");
// Here parentheses are captured as regular tokens, not bracket pairs
auto Pattern2a = t.Pattern("( {etc} (");
auto Pattern2b = t.Pattern(") {etc} )");
cout << "Brackets used as part of pattern" << endl;
cout << "--------------------------------" << endl;
Pattern2a.BracketSensitive(true);
Pattern2b.BracketSensitive(true);
t.Find();
cout << t.Matches().Text() << endl;
cout << "" << endl;
Pattern2a.BracketSensitive(false);
Pattern2b.BracketSensitive(false);
t.Find();
cout << t.Matches().Text() << endl;
}
BracketSensitive: True
----------------------
< a b c >
< (e f g) >
< (i) (j k) >
< m n o ( > p) q >
BracketSensitive: False
-----------------------
< a b c >
< (e f g) >
< (i) (j k) >
< m n o ( >
Brackets used as part of pattern
--------------------------------
( a b (
) d e )
( a b (
) d e ) #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; #define tf(IsTrue) ((IsTrue) ? "True" : "False") int main() { uCalc uc; auto t = uc.NewTransformer(); auto Pattern = t.Pattern("< {etc} >"); t.Str("< a b c > d < (e f g) > h < (i) (j k) > l < m n o ( > p) q >"); // Note the difference in the final match Pattern.BracketSensitive(true); // true is the default cout << "BracketSensitive: " << tf(Pattern.BracketSensitive()) << endl; cout << "----------------------" << endl; t.Find(); cout << t.Matches().Text() << endl; cout << "" << endl; Pattern.BracketSensitive(false); cout << "BracketSensitive: " << tf(Pattern.BracketSensitive()) << endl; cout << "-----------------------" << endl; t.Find(); cout << t.Matches().Text() << endl; cout << "" << endl; t.Str("( a b ( c ) d e )"); // Here parentheses are captured as regular tokens, not bracket pairs auto Pattern2a = t.Pattern("( {etc} ("); auto Pattern2b = t.Pattern(") {etc} )"); cout << "Brackets used as part of pattern" << endl; cout << "--------------------------------" << endl; Pattern2a.BracketSensitive(true); Pattern2b.BracketSensitive(true); t.Find(); cout << t.Matches().Text() << endl; cout << "" << endl; Pattern2a.BracketSensitive(false); Pattern2b.BracketSensitive(false); t.Find(); cout << t.Matches().Text() << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Dim t = uc.NewTransformer()
Dim Pattern = t.Pattern("< {etc} >")
t.Str("< a b c > d < (e f g) > h < (i) (j k) > l < m n o ( > p) q >")
'// Note the difference in the final match
Pattern.BracketSensitive = true '// true is the default
Console.WriteLine($"BracketSensitive: {Pattern.BracketSensitive}")
Console.WriteLine("----------------------")
t.Find()
Console.WriteLine(t.Matches.Text)
Console.WriteLine("")
Pattern.BracketSensitive = false
Console.WriteLine($"BracketSensitive: {Pattern.BracketSensitive}")
Console.WriteLine("-----------------------")
t.Find()
Console.WriteLine(t.Matches.Text)
Console.WriteLine("")
t.Str("( a b ( c ) d e )")
'// Here parentheses are captured as regular tokens, not bracket pairs
Dim Pattern2a = t.Pattern("( {etc} (")
Dim Pattern2b = t.Pattern(") {etc} )")
Console.WriteLine("Brackets used as part of pattern")
Console.WriteLine("--------------------------------")
Pattern2a.BracketSensitive = true
Pattern2b.BracketSensitive = true
t.Find()
Console.WriteLine(t.Matches.Text)
Console.WriteLine("")
Pattern2a.BracketSensitive = false
Pattern2b.BracketSensitive = false
t.Find()
Console.WriteLine(t.Matches.Text)
End Sub
End Module
BracketSensitive: True
----------------------
< a b c >
< (e f g) >
< (i) (j k) >
< m n o ( > p) q >
BracketSensitive: False
-----------------------
< a b c >
< (e f g) >
< (i) (j k) >
< m n o ( >
Brackets used as part of pattern
--------------------------------
( a b (
) d e )
( a b (
) d e ) Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Dim t = uc.NewTransformer() Dim Pattern = t.Pattern("< {etc} >") t.Str("< a b c > d < (e f g) > h < (i) (j k) > l < m n o ( > p) q >") '// Note the difference in the final match Pattern.BracketSensitive = true '// true is the default Console.WriteLine($"BracketSensitive: {Pattern.BracketSensitive}") Console.WriteLine("----------------------") t.Find() Console.WriteLine(t.Matches.Text) Console.WriteLine("") Pattern.BracketSensitive = false Console.WriteLine($"BracketSensitive: {Pattern.BracketSensitive}") Console.WriteLine("-----------------------") t.Find() Console.WriteLine(t.Matches.Text) Console.WriteLine("") t.Str("( a b ( c ) d e )") '// Here parentheses are captured as regular tokens, not bracket pairs Dim Pattern2a = t.Pattern("( {etc} (") Dim Pattern2b = t.Pattern(") {etc} )") Console.WriteLine("Brackets used as part of pattern") Console.WriteLine("--------------------------------") Pattern2a.BracketSensitive = true Pattern2b.BracketSensitive = true t.Find() Console.WriteLine(t.Matches.Text) Console.WriteLine("") Pattern2a.BracketSensitive = false Pattern2b.BracketSensitive = false t.Find() Console.WriteLine(t.Matches.Text) End Sub End Module