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.

FromTo

Method

Product: 

Transformer Library

Class: 

Transformer

Defines a token-aware, find-and-replace rule that transforms text matching a pattern.

Syntax

FromTo(string, string)

Parameters

pattern
string
The uCalc pattern string that defines the text to find. It can contain literals, variables (e.g., `{name}`), and token category matchers (e.g., `{@Number}`).
replacement
string
(Default = "")
The string that will replace the matched text. It can contain literal text, backreferences to captured variables (e.g., `{name}`), and pattern methods (e.g., `{@Eval:...}`).

Return

Rule

Returns the newly created Rule object, which can be used to further configure its behavior (e.g., setting its active state, case-sensitivity, etc.).

Remarks

FromTo is the cornerstone method of the Transformer engine, used to define a find-and-replace rule. It binds a search pattern to a replacement template, allowing for powerful, token-aware text transformations.

⚙️ How It Works

The method takes two primary arguments: a pattern string and a replacement string.

  1. The Pattern String (pattern): This string defines what to search for. It uses uCalc's Pattern Syntax which can include:

    • Literals (Anchors): Exact text that must be present (e.g., "ID:").
    • Variables (Captures): Placeholders like {name} or {@Number:val} that capture dynamic content.
    • Complex Logic: Optional parts ([]), alternations (|), and other structural directives.
  2. The Replacement String (replacement): This string defines how to construct the new text. It can contain:

    • Literal Text: Characters to be inserted as-is.
    • Variable Backreferences: Placeholders like {name} that re-insert the text captured by the corresponding variable in the pattern.
    • Pattern Methods: Powerful directives like {@Eval: ...} to execute code or {!var:default} for conditional logic.

For a complete guide to pattern syntax, see the Patterns section.

🥇 Precedence and Rule Order (LIFO)

A Transformer can have multiple rules. When two or more patterns could potentially match the same text (e.g., "An apple." and "An {item}."), uCalc uses a Last-In, First-Out (LIFO) precedence rule: The most recently defined rule is checked first.

This allows you to define general, catch-all rules first, and then add more specific, higher-precedence rules on top of them.

FromTo vs. Pattern

MethodPurposeReplacement BehaviorUse Case
FromTo(p, r)Find and ReplaceUses the provided replacement string r.Text transformation, data normalization, code generation.
Pattern(p)Find OnlyImplicitly uses {@Self} as the replacement (i.e., re-inserts the matched text).Locating patterns without modifying the source text.

💡 Why uCalc? (Comparative Analysis)

In many languages, string replacement is handled by regular expressions.

  • Standard Regex (Regex.Replace):[csharp]Regex.Replace(input, @"Hello (\w+)", "Greetings, $1");While powerful, regex is purely character-based. It struggles with nested structures, is often difficult to read, and replacement logic is limited to simple backreferences. More complex logic requires using a MatchEvaluator callback, which can be verbose.

  • uCalc FromTo:t.FromTo("Hello {name}", "Greetings, {name}!");uCalc's FromTo offers significant advantages:

    • Readability: Patterns use natural language and variables, making them easier to understand and maintain.
    • Token-Awareness: uCalc is "safe by default." It understands language structures like quotes and brackets, preventing accidental replacements inside string literals or across mismatched parentheses.
    • Embedded Logic: The replacement string can contain conditional logic ({var: ...}) and execute expressions ({@Eval: ...}) directly, which is far more concise than writing a separate callback function.

This makes FromTo a more robust, readable, and powerful tool for any task involving structured text transformation.

Examples

A simple find-and-replace transformation.
				
					using uCalcSoftware;

var uc = new uCalc();
var t = new uCalc.Transformer();
t.FromTo("Hello {name}", "Greetings, {name}!");
Console.WriteLine(t.Transform("Hello World"));
				
			
Greetings, World!
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   uCalc::Transformer t;
   t.FromTo("Hello {name}", "Greetings, {name}!");
   cout << t.Transform("Hello World") << endl;
}
				
			
Greetings, World!
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t As New uCalc.Transformer()
      t.FromTo("Hello {name}", "Greetings, {name}!")
      Console.WriteLine(t.Transform("Hello World"))
   End Sub
End Module
				
			
Greetings, World!
Using ExpressionTransformer to transform expressions before they are parsed
				
					using uCalcSoftware;

var uc = new uCalc();
var ExprT = uc.ExpressionTransformer;  // Transformer used for Eval() and Evaluate()

var p1 = ExprT.FromTo("AddUp({x})", "{x}"); // RewindOnChange False by default
var p2 = ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").SetRewindOnChange(true);

Console.WriteLine($"p1 RewindOnChange: {p1.RewindOnChange}");
Console.WriteLine($"p2 RewindOnChange: {p2.RewindOnChange}");

Console.WriteLine("");

Console.WriteLine($"Input: AddUp(1,2,3,4)");
Console.WriteLine($"Transform: {ExprT.Transform("AddUp(1,2,3,4)")}");
Console.WriteLine($"Eval: {uc.Eval("AddUp(1,2,3,4)")}");
				
			
p1 RewindOnChange: False
p2 RewindOnChange: True

Input: AddUp(1,2,3,4)
Transform: (1 + (2 + (3 + 4)))
Eval: 10
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

#define tf(IsTrue) ((IsTrue) ? "True" : "False")

int main() {
   uCalc uc;
   auto ExprT = uc.ExpressionTransformer();  // Transformer used for Eval() and Evaluate()

   auto p1 = ExprT.FromTo("AddUp({x})", "{x}"); // RewindOnChange False by default
   auto p2 = ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").SetRewindOnChange(true);

   cout << "p1 RewindOnChange: " << tf(p1.RewindOnChange()) << endl;
   cout << "p2 RewindOnChange: " << tf(p2.RewindOnChange()) << endl;

   cout << "" << endl;

   cout << "Input: " << "AddUp(1,2,3,4)" << endl;
   cout << "Transform: " << ExprT.Transform("AddUp(1,2,3,4)") << endl;
   cout << "Eval: " << uc.Eval("AddUp(1,2,3,4)") << endl;
}
				
			
p1 RewindOnChange: False
p2 RewindOnChange: True

Input: AddUp(1,2,3,4)
Transform: (1 + (2 + (3 + 4)))
Eval: 10
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim ExprT = uc.ExpressionTransformer  '// Transformer used for Eval() and Evaluate()
      
      Dim p1 = ExprT.FromTo("AddUp({x})", "{x}") '// RewindOnChange False by default
      Dim p2 = ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").SetRewindOnChange(true)
      
      Console.WriteLine($"p1 RewindOnChange: {p1.RewindOnChange}")
      Console.WriteLine($"p2 RewindOnChange: {p2.RewindOnChange}")
      
      Console.WriteLine("")
      
      Console.WriteLine($"Input: AddUp(1,2,3,4)")
      Console.WriteLine($"Transform: {ExprT.Transform("AddUp(1,2,3,4)")}")
      Console.WriteLine($"Eval: {uc.Eval("AddUp(1,2,3,4)")}")
   End Sub
End Module
				
			
p1 RewindOnChange: False
p2 RewindOnChange: True

Input: AddUp(1,2,3,4)
Transform: (1 + (2 + (3 + 4)))
Eval: 10
Maximum, GlobalMaximum
				
					using uCalcSoftware;

var uc = new uCalc();
var FruitsXML =
"""

<Fruits>
  <Fruit CommonName='Apple' ScientificName='Malus domestica' />
  <Fruit CommonName='Banana' ScientificName='Musa acuminata' />
  <Fruit CommonName='Orange' ScientificName='Citrus × sinensis' />
  <Fruit CommonName='Grapes' ScientificName='Vitis vinifera' />
  <Fruit CommonName='Strawberry' ScientificName='Fragaria × ananassa' />
  <Fruit CommonName='Pineapple' ScientificName='Ananas comosus' />
  <Fruit CommonName='Mango' ScientificName='Mangifera indica' />
  <Fruit CommonName='Blueberry' ScientificName='Vaccinium corymbosum' />
  <Fruit CommonName='Rambutan' ScientificName='Nephelium lappaceum' />
  <Fruit CommonName='Salak (Snake Fruit)' ScientificName='Salacca zalacca' />
  <Fruit CommonName='Jabuticaba' ScientificName='Plinia cauliflora' />
  <Fruit CommonName='Watermelon' ScientificName='Citrullus lanatus' />
</Fruits>

""";

uc.DefineVariable("x");
var t = uc.NewTransformer();
var FruitsTag = t.FromTo("<Fruits>", "List of fruits");
var Fruit = t.FromTo("CommonName={@string:name}", "{@Eval: x++}. {name}");

uc.Eval("x = 1");
Fruit.Maximum = 10;
t.Filter(FruitsXML);
Console.WriteLine($"Maximum = {Fruit.Maximum}");
Console.WriteLine($"Matches count: {t.Matches.Count()}"); // 1 for FruitsTag occurrence
Console.WriteLine("");
Console.WriteLine(t.Matches);
Console.WriteLine("");
Console.WriteLine("===============");

uc.Eval("x = 1");
Fruit.Maximum = 20;
t.Filter(FruitsXML);
Console.WriteLine($"Maximum = {Fruit.Maximum}");
Console.WriteLine($"Matches count: {t.Matches.Count()}"); // 1 for FruitsTag plus 12 fruits
Console.WriteLine("");
Console.WriteLine(t.Matches);
Console.WriteLine("");
Console.WriteLine("===============");

uc.Eval("x = 1");
Fruit.GlobalMaximum = 10; // Notice "List of fruits" will not show
t.Filter(FruitsXML);
Console.WriteLine($"MaximumAND = {Fruit.GlobalMaximum}");
Console.WriteLine($"Matches count: {t.Matches.Count()}"); // Even FruitsTage won't be counted
Console.WriteLine("");
Console.WriteLine(t.Matches);
Console.WriteLine("===============");

uc.Eval("x = 1");
Fruit.GlobalMaximum = 20;
t.Filter(FruitsXML);
Console.WriteLine($"MaximumAND = {Fruit.GlobalMaximum}");
Console.WriteLine($"Matches count: {t.Matches.Count()}");
Console.WriteLine("");
Console.WriteLine(t.Matches);

				
			
Maximum = 10
Matches count: 1

List of fruits

===============
Maximum = 20
Matches count: 13

List of fruits
1. Apple
2. Banana
3. Orange
4. Grapes
5. Strawberry
6. Pineapple
7. Mango
8. Blueberry
9. Rambutan
10. Salak (Snake Fruit)
11. Jabuticaba
12. Watermelon

===============
MaximumAND = 10
Matches count: 0


===============
MaximumAND = 20
Matches count: 13

List of fruits
1. Apple
2. Banana
3. Orange
4. Grapes
5. Strawberry
6. Pineapple
7. Mango
8. Blueberry
9. Rambutan
10. Salak (Snake Fruit)
11. Jabuticaba
12. Watermelon
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   auto FruitsXML =
   R"(
<Fruits>
  <Fruit CommonName='Apple' ScientificName='Malus domestica' />
  <Fruit CommonName='Banana' ScientificName='Musa acuminata' />
  <Fruit CommonName='Orange' ScientificName='Citrus × sinensis' />
  <Fruit CommonName='Grapes' ScientificName='Vitis vinifera' />
  <Fruit CommonName='Strawberry' ScientificName='Fragaria × ananassa' />
  <Fruit CommonName='Pineapple' ScientificName='Ananas comosus' />
  <Fruit CommonName='Mango' ScientificName='Mangifera indica' />
  <Fruit CommonName='Blueberry' ScientificName='Vaccinium corymbosum' />
  <Fruit CommonName='Rambutan' ScientificName='Nephelium lappaceum' />
  <Fruit CommonName='Salak (Snake Fruit)' ScientificName='Salacca zalacca' />
  <Fruit CommonName='Jabuticaba' ScientificName='Plinia cauliflora' />
  <Fruit CommonName='Watermelon' ScientificName='Citrullus lanatus' />
</Fruits>
)";

   uc.DefineVariable("x");
   auto t = uc.NewTransformer();
   auto FruitsTag = t.FromTo("<Fruits>", "List of fruits");
   auto Fruit = t.FromTo("CommonName={@string:name}", "{@Eval: x++}. {name}");

   uc.Eval("x = 1");
   Fruit.Maximum(10);
   t.Filter(FruitsXML);
   cout << "Maximum = " << Fruit.Maximum() << endl;
   cout << "Matches count: " << t.Matches().Count() << endl; // 1 for FruitsTag occurrence
   cout << "" << endl;
   cout << t.Matches() << endl;
   cout << "" << endl;
   cout << "===============" << endl;

   uc.Eval("x = 1");
   Fruit.Maximum(20);
   t.Filter(FruitsXML);
   cout << "Maximum = " << Fruit.Maximum() << endl;
   cout << "Matches count: " << t.Matches().Count() << endl; // 1 for FruitsTag plus 12 fruits
   cout << "" << endl;
   cout << t.Matches() << endl;
   cout << "" << endl;
   cout << "===============" << endl;

   uc.Eval("x = 1");
   Fruit.GlobalMaximum(10); // Notice "List of fruits" will not show
   t.Filter(FruitsXML);
   cout << "MaximumAND = " << Fruit.GlobalMaximum() << endl;
   cout << "Matches count: " << t.Matches().Count() << endl; // Even FruitsTage won't be counted
   cout << "" << endl;
   cout << t.Matches() << endl;
   cout << "===============" << endl;

   uc.Eval("x = 1");
   Fruit.GlobalMaximum(20);
   t.Filter(FruitsXML);
   cout << "MaximumAND = " << Fruit.GlobalMaximum() << endl;
   cout << "Matches count: " << t.Matches().Count() << endl;
   cout << "" << endl;
   cout << t.Matches() << endl;

}
				
			
Maximum = 10
Matches count: 1

List of fruits

===============
Maximum = 20
Matches count: 13

List of fruits
1. Apple
2. Banana
3. Orange
4. Grapes
5. Strawberry
6. Pineapple
7. Mango
8. Blueberry
9. Rambutan
10. Salak (Snake Fruit)
11. Jabuticaba
12. Watermelon

===============
MaximumAND = 10
Matches count: 0


===============
MaximumAND = 20
Matches count: 13

List of fruits
1. Apple
2. Banana
3. Orange
4. Grapes
5. Strawberry
6. Pineapple
7. Mango
8. Blueberry
9. Rambutan
10. Salak (Snake Fruit)
11. Jabuticaba
12. Watermelon
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim FruitsXML =
      "
<Fruits>
  <Fruit CommonName='Apple' ScientificName='Malus domestica' />
  <Fruit CommonName='Banana' ScientificName='Musa acuminata' />
  <Fruit CommonName='Orange' ScientificName='Citrus × sinensis' />
  <Fruit CommonName='Grapes' ScientificName='Vitis vinifera' />
  <Fruit CommonName='Strawberry' ScientificName='Fragaria × ananassa' />
  <Fruit CommonName='Pineapple' ScientificName='Ananas comosus' />
  <Fruit CommonName='Mango' ScientificName='Mangifera indica' />
  <Fruit CommonName='Blueberry' ScientificName='Vaccinium corymbosum' />
  <Fruit CommonName='Rambutan' ScientificName='Nephelium lappaceum' />
  <Fruit CommonName='Salak (Snake Fruit)' ScientificName='Salacca zalacca' />
  <Fruit CommonName='Jabuticaba' ScientificName='Plinia cauliflora' />
  <Fruit CommonName='Watermelon' ScientificName='Citrullus lanatus' />
</Fruits>
"
      
      uc.DefineVariable("x")
      Dim t = uc.NewTransformer()
      Dim FruitsTag = t.FromTo("<Fruits>", "List of fruits")
      Dim Fruit = t.FromTo("CommonName={@string:name}", "{@Eval: x++}. {name}")
      
      uc.Eval("x = 1")
      Fruit.Maximum = 10
      t.Filter(FruitsXML)
      Console.WriteLine($"Maximum = {Fruit.Maximum}")
      Console.WriteLine($"Matches count: {t.Matches.Count()}") '// 1 for FruitsTag occurrence 
      Console.WriteLine("")
      Console.WriteLine(t.Matches)
      Console.WriteLine("")
      Console.WriteLine("===============")
      
      uc.Eval("x = 1")
      Fruit.Maximum = 20
      t.Filter(FruitsXML)
      Console.WriteLine($"Maximum = {Fruit.Maximum}")
      Console.WriteLine($"Matches count: {t.Matches.Count()}") '// 1 for FruitsTag plus 12 fruits
      Console.WriteLine("")
      Console.WriteLine(t.Matches)
      Console.WriteLine("")
      Console.WriteLine("===============")
      
      uc.Eval("x = 1")
      Fruit.GlobalMaximum = 10 '// Notice "List of fruits" will not show
      t.Filter(FruitsXML)
      Console.WriteLine($"MaximumAND = {Fruit.GlobalMaximum}")
      Console.WriteLine($"Matches count: {t.Matches.Count()}") '// Even FruitsTage won't be counted
      Console.WriteLine("")
      Console.WriteLine(t.Matches)
      Console.WriteLine("===============")
      
      uc.Eval("x = 1")
      Fruit.GlobalMaximum = 20
      t.Filter(FruitsXML)
      Console.WriteLine($"MaximumAND = {Fruit.GlobalMaximum}")
      Console.WriteLine($"Matches count: {t.Matches.Count()}")
      Console.WriteLine("")
      Console.WriteLine(t.Matches)
      
   End Sub
End Module
				
			
Maximum = 10
Matches count: 1

List of fruits

===============
Maximum = 20
Matches count: 13

List of fruits
1. Apple
2. Banana
3. Orange
4. Grapes
5. Strawberry
6. Pineapple
7. Mango
8. Blueberry
9. Rambutan
10. Salak (Snake Fruit)
11. Jabuticaba
12. Watermelon

===============
MaximumAND = 10
Matches count: 0


===============
MaximumAND = 20
Matches count: 13

List of fruits
1. Apple
2. Banana
3. Orange
4. Grapes
5. Strawberry
6. Pineapple
7. Mango
8. Blueberry
9. Rambutan
10. Salak (Snake Fruit)
11. Jabuticaba
12. Watermelon