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.

{@Newline}

Product: 

Class: 

Remarks

Shortcut: {@nl}

Description: A category matcher that identifies any token defined as a vertical line break (e.g., \n or \r\n).

The {@Newline} directive (shorthand {@nl}) is used in a uCalc::Transformer to target vertical structural boundaries. Unlike generic whitespace matchers in other languages, uCalc maintains a strict distinction between horizontal and vertical spacing to preserve document structure during complex transformations.

Vertical vs. Horizontal Space

In uCalc, newlines are treated as a distinct category of tokens. This prevents rules intended for horizontal cleanup from accidentally collapsing multiple lines into a single one.

  • {@Whitespace}: Targets spaces and tabs.
  • {@Newline}: Targets line-ending characters.

The _newline Variable

The actual string character(s) used by the {@nl} directive is controlled by a special internal string variable named _newline.

  • Default Behavior: By default, _newline is set to \r\n (CRLF) for versions compiled for Windows, and \n (LF) for all other platforms.
  • Reconfiguration: You can manually override the newline character used for output by redefining this variable in the evaluator. This is useful for cross-platform document normalization.
    • Example: uc.Eval("_newline = '\n'"); sets the newline to Unix-style globally.

Common Behaviors

  • Statement Boundaries: In many programming languages, a newline signifies the end of a command. {@nl} allows rules to be anchored specifically to the "End of Line" context.
  • Cleanup Logic: Consecutive newlines can be matched and reduced (e.g., matching three newlines and replacing with two) to normalize document formatting.
  • The Inverse Operator (!): Using {!nl} allows the engine to match any token that is not a line break, which is useful for processing content while ensuring the match does not spill over into the next line.

Short Alias

Because vertical alignment is a frequent requirement in transformation patterns, the shorter {@nl} alias is provided for cleaner, more readable rule definitions.


Examples

1. Succinct (Quick Start: Consolidating Space)

Replacing triple-newlines with a standard double-newline to normalize document spacing.

New(uCalc::Transformer, t)// Match three consecutive newline tokenst.FromTo("{@nl} {@nl} {@nl}", "{@nl}{@nl}")wl(t.Transform("Line 1\n\n\nLine 2"))

[Expected Output]Line 1 Line 2

2. Practical (Real World: Line Counting)

Using {@@Exec} to increment a counter every time a newline is encountered, then displaying the total at the end.

New(uCalc::Transformer, t)// Initialize line counter at the start of the doct.FromTo("{@Beginning}", "{@Exec: Variable: lncnt = 1}")// For every newline, increment the countert.FromTo("{@nl}", "{@@Exec: lncnt = lncnt + 1}{@Self}")// At the end, show the line countt.FromTo("{@End}", " [Total Lines: {@@Eval: lncnt}]")wl(t.Transform("A\nB\nC"))

[Expected Output]ABC [Total Lines: 3]

3. Internal Test (Ignoring Horizontal Space)

Verifying that {@nl} ignores horizontal whitespace (tabs and spaces) and only triggers on true vertical breaks.

New(uCalc::Transformer, t)t.FromTo("{@nl}", "[BREAK]")// The spaces between 'A' and 'B' should remain untouchedwl(t.Transform("A   B\nC"))

[Expected Output]A B[BREAK]C


Strategy & Critique

  • Structural Safety: The categorical separation of {@ws} and {@nl} ensures that developers can perform aggressive horizontal whitespace normalization without worrying about losing the vertical "shape" of the code or document.
  • Performance: Because newlines are identified during the initial lexing phase, matching {@nl} is significantly faster than using a regex that has to backtrack through various whitespace combinations.
  • Critique: One potential pitfall for new users is forgetting that \r\n (Windows style) is often treated as a single token. {@nl} handles this automatically, but capturing the newline into a variable might yield different raw string values depending on the source document's encoding.
  • See Also: Refer to Topic 801 ({@Whitespace}) for horizontal spacing control.

Examples

Matching by token type
				
					using uCalcSoftware;

var uc = new uCalc();
var t = uc.NewTransformer();

t.FromTo("{@String:txt}", "<<InnerQuote={txt}><TxtWithQuotes={txt(0)}>>");
t.FromTo("{@Number:MyNum}", "<NumericValue={MyNum}>");
t.FromTo("{@Bracket:MyBrack}", "<Brack={MyBrack}>");
t.FromTo("{@CloseBracket:CloseBr}", "<CloseBrack={CloseBr}>");
t.FromTo("{@StatementSeparator:Sep}", "<Separator={Sep}>");
t.FromTo("{@Alphanumeric:alpha}", "<Alpha={alpha}>");
t.FromTo("{@Whitespace:ws}", "<whitespace count={@Eval: Length(ws)}>");
t.FromTo("{@Reducible:r}", "<Reducible={r}>");
t.FromTo("{@Newline}", "<New line{@Newline}>");

var s = """
This is   55.2*6 "Hello world";
'Single quote'(parenth)
""";

Console.WriteLine(t.Filter(s).Matches.Text);
				
			
<Alpha=This>
<whitespace count=1>
<Alpha=is>
<whitespace count=3>
<NumericValue=55.2>
<Reducible=*>
<NumericValue=6>
<whitespace count=1>
<<InnerQuote=Hello world><TxtWithQuotes="Hello world">>
<Separator=;>
<New line
>
<<InnerQuote=Single quote><TxtWithQuotes='Single quote'>>
<Brack=(>
<Alpha=parenth>
<CloseBrack=)>
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   auto t = uc.NewTransformer();

   t.FromTo("{@String:txt}", "<<InnerQuote={txt}><TxtWithQuotes={txt(0)}>>");
   t.FromTo("{@Number:MyNum}", "<NumericValue={MyNum}>");
   t.FromTo("{@Bracket:MyBrack}", "<Brack={MyBrack}>");
   t.FromTo("{@CloseBracket:CloseBr}", "<CloseBrack={CloseBr}>");
   t.FromTo("{@StatementSeparator:Sep}", "<Separator={Sep}>");
   t.FromTo("{@Alphanumeric:alpha}", "<Alpha={alpha}>");
   t.FromTo("{@Whitespace:ws}", "<whitespace count={@Eval: Length(ws)}>");
   t.FromTo("{@Reducible:r}", "<Reducible={r}>");
   t.FromTo("{@Newline}", "<New line{@Newline}>");

   auto s = R"(This is   55.2*6 "Hello world";
'Single quote'(parenth))";

   cout << t.Filter(s).Matches().Text() << endl;
}
				
			
<Alpha=This>
<whitespace count=1>
<Alpha=is>
<whitespace count=3>
<NumericValue=55.2>
<Reducible=*>
<NumericValue=6>
<whitespace count=1>
<<InnerQuote=Hello world><TxtWithQuotes="Hello world">>
<Separator=;>
<New line
>
<<InnerQuote=Single quote><TxtWithQuotes='Single quote'>>
<Brack=(>
<Alpha=parenth>
<CloseBrack=)>
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t = uc.NewTransformer()
      
      t.FromTo("{@String:txt}", "<<InnerQuote={txt}><TxtWithQuotes={txt(0)}>>")
      t.FromTo("{@Number:MyNum}", "<NumericValue={MyNum}>")
      t.FromTo("{@Bracket:MyBrack}", "<Brack={MyBrack}>")
      t.FromTo("{@CloseBracket:CloseBr}", "<CloseBrack={CloseBr}>")
      t.FromTo("{@StatementSeparator:Sep}", "<Separator={Sep}>")
      t.FromTo("{@Alphanumeric:alpha}", "<Alpha={alpha}>")
      t.FromTo("{@Whitespace:ws}", "<whitespace count={@Eval: Length(ws)}>")
      t.FromTo("{@Reducible:r}", "<Reducible={r}>")
      t.FromTo("{@Newline}", "<New line{@Newline}>")
      
      Dim s = "This is   55.2*6 ""Hello world"";
'Single quote'(parenth)"
      
      Console.WriteLine(t.Filter(s).Matches.Text)
   End Sub
End Module
				
			
<Alpha=This>
<whitespace count=1>
<Alpha=is>
<whitespace count=3>
<NumericValue=55.2>
<Reducible=*>
<NumericValue=6>
<whitespace count=1>
<<InnerQuote=Hello world><TxtWithQuotes="Hello world">>
<Separator=;>
<New line
>
<<InnerQuote=Single quote><TxtWithQuotes='Single quote'>>
<Brack=(>
<Alpha=parenth>
<CloseBrack=)>