Class NcPatchUtil
- Namespace
- Hi.NcParsers.NcWriteback
- Assembly
- HiMech.dll
Positional text-edit primitives for NcPatchWriter (the patch-mode INcPieceConverter): anchored token edits on a verbatim BlockText draft.
This is the SoftNc dual of HardNcUtil.SetTagNumber/AddBySeq
with the two known defects fixed while keeping every other semantic:
- Edits splice by match index (
Remove/Insert) instead ofstring.Replace(m.Value, …), so a literal that repeats elsewhere in the text is never also rewritten (the positional-reverse convention of GrabTagValue(ref string, IEnumerable<string>, string)). - Numbers are formatted with InvariantCulture (HardNc used the current culture).
Faithfully kept from HardNc: NaN deletes the token; an absent tag is
inserted at the conventional word position
(ConventionalTagOrder: X,Y,Z,I,J,K,A,B,C,F,S — X scans
forward for the first present successor and lands before it, other tags
scan backward for the nearest present predecessor and land after it,
otherwise the token is appended at the end of the code region);
formatted values trim trailing zeros but keep the decimal point
(10.0000 → 10.), which also guards the value against
no-decimal-point integer shrinking on replay.
Tag matching mirrors the parser's lexing exactly (GrabTagValue(ref string, IEnumerable<string>, string): case-insensitive, RegexFlagPrefix guard, and the full value grammar number|variable|bracket-expression) so that patch and parse agree on what a token is. A tag whose value is a variable or bracket expression is refused, never rewritten.
public static class NcPatchUtil
- Inheritance
-
NcPatchUtil
- Inherited Members
Fields
ConventionalTagOrder
Conventional Fanuc-style word order used when inserting an absent tag
(mirrors HardNcUtil.AddBySeq).
public static readonly string[] ConventionalTagOrder
Field Value
- string[]
Methods
FormatTagNumber(double, string)
Formats a tag number per the HardNc writeback convention:
InvariantCulture, trailing zeros after the
decimal point trimmed while the dot itself is kept
(-50.2500 → -50.25, 10.0000 → 10.).
Shared by the patch primitives and FanucNcSentenceComposer.
public static string FormatTagNumber(double value, string format)
Parameters
Returns
GetTagNumber(string, string, string, IReadOnlyList<(int Start, int Length)>, IReadOnlyList<string>)
Reads the numeric literal of the first unprotected token of
tag in blockText; NaN when the
tag is absent or carries a variable/bracket/keyword value. Uses
exactly the value grammar of SetTagNumber(ref string, string, double, string, string, IReadOnlyList<(int Start, int Length)>, IReadOnlyList<string>, bool, bool)
(TagValuePattern), so a read and a subsequent edit agree on
the token. The literal is parsed raw
(InvariantCulture) — no dialect
integer-shrink scaling is applied, unlike the parser's
SoftNcUtil.GrabDouble(…, enableIntegerShrink); splition-plan
callers read decimal-pointed arc words (I/J/K/R) where the raw
literal equals the parsed value.
public static double GetTagNumber(string blockText, string tag, string varPrefix = "#", IReadOnlyList<(int Start, int Length)> protectedSpans = null, IReadOnlyList<string> keywordValues = null)
Parameters
blockTextstringNC block text to read; null counts as empty.
tagstringTag to look for, e.g.
“I”.varPrefixstringVariable index prefix of the dialect.
protectedSpansIReadOnlyList<(int Start, int Length)>Comment spans to skip.
keywordValuesIReadOnlyList<string>Dialect keywords that can stand where the tag's number would be; null for dialects without keyword values.
Returns
IsCarriedSection(JsonObject, string)
True when the piece's section was injected by the pipeline
(AddedByKey present: a
ModalCarrySyntax clone or a backfill) rather than authored from
the block's own text. A carried section's token is guaranteed absent
from BlockText — a patch must not anchor on it,
and a strip is a no-op.
One-way signal only: an AddedBy-less section can still lack a literal
token (modal-lookback syntaxes such as FeedrateSyntax re-author
sections without stamping). The final authority on literal presence is
the anchored text match itself.
public static bool IsCarriedSection(JsonObject json, string sectionKey)
Parameters
jsonJsonObjectsectionKeystring
Returns
ProbeTagValue(string, string, string, IReadOnlyList<(int Start, int Length)>, IReadOnlyList<string>)
Probes what the first unprotected literal token of tag
carries in blockText, using exactly the value grammar
(TagValuePattern: number | variable/bracket expression | dialect
keyword) that SetTagNumber(ref string, string, double, string, string, IReadOnlyList<(int Start, int Length)>, IReadOnlyList<string>, bool, bool) matches against — so a probe
and a subsequent edit can never disagree on token presence or
editability.
public static NcTagValueKind ProbeTagValue(string blockText, string tag, string varPrefix = "#", IReadOnlyList<(int Start, int Length)> protectedSpans = null, IReadOnlyList<string> keywordValues = null)
Parameters
blockTextstringNC block text to probe; null counts as empty.
tagstringTag to look for, e.g.
“F”.varPrefixstringVariable index prefix of the dialect (Fanuc
#, HeidenhainQ).protectedSpansIReadOnlyList<(int Start, int Length)>Comment spans to skip (see GetFanucCommentSpans(string)).
keywordValuesIReadOnlyList<string>Dialect keywords that can stand where the tag's number would be; null for dialects without keyword values.
Returns
RemoveFlag(ref string, string, IReadOnlyList<(int Start, int Length)>)
Removes the first whole-token occurrence of flagRegex
from blockText by positional splice, absorbing one
adjacent separator space. Matching is case-insensitive with the
RegexFlagPrefix prefix guard and a
(?![0-9]) tail guard — the numbered-flag lexing: the token ends
at its digits, so glued words match (G01X1.) while a longer
number does not (G1 never bites G17). Dotted variants
are the caller's responsibility (strip G43.4 before
G43).
This is the text half of modal-token stripping (one line split into many keeps the modal G word only on the first fragment); use IsCarriedSection(JsonObject, string) first — a carried section's token is not in the source text at all, so no removal should be attempted.
public static bool RemoveFlag(ref string blockText, string flagRegex, IReadOnlyList<(int Start, int Length)> protectedSpans = null)
Parameters
Returns
- bool
True when a token was found and removed.
RemoveFlagTrimmingTail(ref string, string, IReadOnlyList<(int Start, int Length)>)
Removes the first whole-token occurrence of flagRegex
with the HardNc splition byte shape: the token span is cut out and the
REMAINDER after it is TrimStart()ed — the exact splice of the
oracle's RebuildFlagSyntaxToNcLine (frozen baseline,
HiNc/NcOpt/NcOptProc.cs:1985-1989), which differs from
RemoveFlag(ref string, string, IReadOnlyList<(int Start, int Length)>) when the token sits at the end of the code
region (the oracle keeps the preceding space; the absorbing removal
would eat it). The tail guard here is (?![0-9.]) — one
character stronger than the oracle's guard-less regex — so a plain
name never bites its dotted variant (G54 vs G54.1);
the oracle avoids those bites through its flag-state gate instead.
public static bool RemoveFlagTrimmingTail(ref string blockText, string flagRegex, IReadOnlyList<(int Start, int Length)> protectedSpans = null)
Parameters
blockTextstringNC block text to edit.
flagRegexstringEscaped literal flag token, e.g.
“G94”.protectedSpansIReadOnlyList<(int Start, int Length)>Comment spans to skip.
Returns
- bool
True when a token was found and removed.
SetTagNumber(ref string, string, double, string, string, IReadOnlyList<(int Start, int Length)>, IReadOnlyList<string>, bool, bool)
Sets, replaces, or deletes a single tag value token in
blockText by positional splice.
Dual of HardNcUtil.SetTagNumber: a found tag is rewritten in
place (NaN removes the whole token together with one adjacent
separator space); an absent tag with a non-NaN value is inserted at
its conventional word position. The original tag letter casing is
preserved on replace; only the addressed token's span changes, so an
edit to F can never diff anything but F.
public static NcPatchTagResult SetTagNumber(ref string blockText, string tag, double tagNumber, string tagNumberFormat, string varPrefix = "#", IReadOnlyList<(int Start, int Length)> protectedSpans = null, IReadOnlyList<string> keywordValues = null, bool absorbSeparatorSpaceOnRemove = true, bool rewriteEqualLiteral = false)
Parameters
blockTextstringNC block text to edit (verbatim draft).
tagstringTag to address, e.g.
“F”,“X”.tagNumberdoubleNew value; NaN deletes the token.
tagNumberFormatstringNumeric format, e.g.
“F2”/“F4”(see FormatTagNumber(double, string)).varPrefixstringVariable index prefix of the dialect (Fanuc
#, HeidenhainQ) — used to recognize, and refuse, variable values.protectedSpansIReadOnlyList<(int Start, int Length)>Comment spans to skip; matches and insertions never land inside them (see GetFanucCommentSpans(string)).
keywordValuesIReadOnlyList<string>Dialect keywords that can stand where the tag's number would be (e.g. Heidenhain
MAX/AUTOafterF); a keyword-valued tag is refused, never treated as absent.absorbSeparatorSpaceOnRemoveboolWhether a NaN-value removal also absorbs one adjacent separator space (the default). Pass false for the HardNc splition-fragment byte shape: the oracle's
HardNcUtil.SetTagNumberdeletes withstring.Replace(match, ""), leaving both separators in place (HiUniNc/Numerical/HardNcUtil.cs:466-467) — e.g. deleting the trailing F of"… Z-1.9 F4000."keeps the space, so the embedded-log note lands as"… Z-1. (src(…))"with a doubled space, which the fragment rewrite must reproduce byte-for-byte.rewriteEqualLiteralboolWhether to rewrite a literal that already means the requested value, re-spelling it in canonical format instead of keeping the original bytes (the default keeps them). The HardNc oracle always rewrites (
HiUniNc/Numerical/HardNcUtil.cs:470-475), so the splition fragment path passes true for byte parity — e.g. a sourceI0.0under an unchanged center re-spells asI0.in the reference output, which the byte-stability shortcut would otherwise keep asI0.0.