🚀 Get to pre-production in weeks, not months, with private training direct from Jube’s developer — real sovereignty, zero vendor lock-in.
Tokens
Jube relies on the injection of VB .Net code which is subsequently complied by reflection in the .net core runtime. While this allows for extremely fast rules to be created it does expose security issues in the possibility of code injection. This code injection could be sinister given the breadth of the .net API (although the Jube instance should be run with the least privileges, not needing to perform any disk IO or operating system level interaction beyond logging, and even logging can be offloaded via syslog).
To ensure that malicious code cannot be been injected, an integrity check on the all code created by the user is performed before compile on creation and in the background during model synchronisation. In the event that the code does not pass an integrity check, it would be bypassed, with ERROR level being written to the logs.
Compile Diagnostics
Activation Rules, Gateway Rules, Abstraction Rules, Abstraction Calculations, Inline Functions and Inline Scripts each carry Compiled (boolean) and CompileError (text) columns on their own table, updated on every compile attempt - both on save and during background model synchronisation. An active rule whose last compile in the engine failed is reported, with the engine’s own error, as Did not compile in the engine on the Model Integrity page. The columns can also be queried directly, for example:
select "Id", "Name", "Compiled", "CompileError"
from "EntityAnalysisModelActivationRule"
where "Compiled" = 0
Failures not tied to a specific rule row (general synchronisation errors) are instead recorded to the EntityAnalysisModelSynchronisationError table (SynchronisationStepId, ErrorMessage, CreatedDate), also only queryable directly.
Compiled Assembly Cache Observability
Compiled rule assemblies (the .NET binaries produced by reflection-compiling rule scripts) are held in an in-memory cache, keyed by a hash of the script text, so that an unchanged rule is never recompiled. This cache has no eviction of its own, so a background task snapshots it periodically (WaitHashCacheAssemblyObservability, default 60000ms - see Environment Variables) to three tables, so growth over time can be observed:
HashCacheAssemblyInstance- one row per running instance (identified by hostname and a Guid generated at startup), holding the instance’s current entry Count and total Bytes.HashCacheAssemblyInstanceJournal- a time-series history, one row per snapshot per instance, of Count and Bytes - this is what shows growth (or a leak) over time rather than only the current total.HashCacheAssemblyInstanceEntry- one row per distinct compiled script (by ScriptHash, upserted so a restart does not rewrite the row for an already-known hash), storing the compiled size, the original rule Code, and the raw compiled Binary (PE bytes) - the Binary can be decompiled to audit exactly what was compiled and is running for a given script hash.
There is no administrative page for any of this - it is intended to be queried directly, for example:
select "Instance", "Count", "Bytes", "UpdatedDate"
from "HashCacheAssemblyInstance"
Rule Author Syntax vs. Internal Token Representation
Everything from here to the end of this section - the hardcoded token list and the worked soft-parse walkthrough - describes what the compiler produces internally, after a rule is saved, not what a rule author types. A rule is always written in plain dot notation against a token; the compiler rewrites it, before the integrity check below ever runs, into a different internal form. Some internal forms differ from what was written by more than just added parentheses, and three of the internal-only names (Data, KVP, Calculation) are never valid to type directly in a rule - they only ever exist after translation. The full mapping, verified against Jube.Parser.Parser.TranslateFromDotNotation:
| Written by the rule author | Compiled to internally |
|---|---|
Payload.FieldName | Data("FieldName").AsString() (or .AsInt() / .AsDouble() / .AsDateTime() / .AsBool, chosen automatically from the field’s data type) |
Abstraction.FieldName | Abstraction("FieldName") |
AbstractionCalculation.FieldName | Calculation("FieldName") |
Activation.FieldName | Activation.Contains("FieldName") |
TTLCounter.FieldName | TTLCounter("FieldName") |
List.FieldName | List("FieldName") |
Dictionary.FieldName | KVP("FieldName") |
Sanction.FieldName | Sanctions.GetValueOrThrow("FieldName") |
ExhaustiveAdaptation.FieldName | ExhaustiveAdaptation("FieldName") |
HttpAdaptation.FieldName | HTTPAdaptation("FieldName") (see HTTP Adaptation Protocol) |
If you are writing a rule, use the left-hand column - that is the only syntax a rule author should ever copy from this page. The rest of this section documents the right-hand column, i.e. what the integrity check actually validates, purely so the diagnostics and error messages it produces make sense.
All tokens inside a rule must be registered in the RuleScriptToken table in the database:
select *
from "RuleScriptToken"
There are some default tokens which are embedded into the parser already, supporting the basic logic statements and the internal names produced by the translation above. The following tokens are hard coded (verified against Jube.Parser.Parser’s constructor):
{“Return”,”If”,”Then”,”End If”,”False”,”True”,”Payload”,”Abstraction”,”Activation”,”ExhaustiveAdaptation”, “HttpAdaptation”,”Select”,”Case”,”End Select”,”Contains”,”StartsWith”,”EndsWith”,”Sanctions”,”KVP”,”List”,”TTLCounter”,”String”,”Double”, “Integer”,”DateTime”,”AsString”,”AsInt”,”AsDouble”,”AsDateTime”,”AsBool”,”Data”,”Calculation”,”Not”,”AND”,”OR”, “GetValueOrThrow”}
Of these, only Payload, Abstraction, Activation, TTLCounter, List, ExhaustiveAdaptation and HttpAdaptation ever appear as something a rule author typed - and even then only as a defensive fallback, since a well-formed rule has already had them rewritten by the translation step before the integrity check runs. Data, KVP, Calculation, Sanctions, GetValueOrThrow, AsString, AsInt, AsDouble, AsDateTime and AsBool exist purely so the translated text can pass the check; a rule author has no reason to type any of them.
HttpAdaptation carries the full HTTP Adaptation Protocol response, not a bare score - see the HTTP Adaptation Protocol page. The Adaptation object returned implicitly converts to the underlying score wherever a numeric context expects one, so no .Value suffix is generated or required.
The parse function takes a string containing a VB .Net code fragment and performs several steps to parse for integrity. For the purposes of this example, the following rule will be parsed for integrity:
If Payload.Name = "Richard" Then
Matched = True
End If
The first step of the parse is to break the rule into its component lines on CrLf, Cr or Lf. Each line will be parsed one by one.
Before the soft parser sees the line at all, it has already been through the translation step in the table above: Payload.Name (what the author wrote) becomes Data("Name").AsString() (the internal form). Enclosed strings are then removed as they are allowed to contain a multitude of data - in this example, both "Name" (now inside the translated Data(...) call) and "Richard" are enclosed strings. The soft parser will now see the line as follows - note that it is Data, not Payload, that actually gets validated here:
If Data().AsString() = Then
The soft parse breaks the line into tokens, to check that the tokens exist in the registry. The line is split based upon the following array of allowed characters:
{“,”, “ “, “(“, “)”, “=”, “>”, “<”, “>=”, “<=”, “<>”, “.”, “_”,”+”,”-“,”/”,”*”,”&”}
The soft parser will now see an array as follows:
{“If”,”Data”,”AsString”,”Then”}
Each token will be checked for integrity. Firstly, the token will be tested to see if it is numeric, and if so, no further integrity checking on that token will take place. Assuming that the token is not numeric, it will be validated against the list of allowed tokens. The base assumption is that the rule string is not valid and all tokens must be found in order for the line to be considered as being valid.
There is a curious case of valid language tokens such a “End If” which is logically a single token, but would be read as two tokens. As seen above, it is possible to store such logical tokens in the registry.
For each token stored in the database or hardcoded, a test token will be taken and a match will be sought (i.e. looking one by one, for each token) against the registry of tokens. If a match is found, the integrity of that token will be declared valid, and it will move onto the next token.
Any token that does not find a corresponding match or entry in the registry will be declared invalid, which is enough for the entire integrity of the rule text to be declared invalid, although the routine will continue to run, reporting out all problematic tokens to the error logs.
To deal with the unusual case where a token in the registry is separated by a space, depending on the number of spaces in the token registry entry, the test token will be reconstructed for that same number of subsequent tokens awaiting test (for example End, which is not allowed, is reconstructed to End If). This is because to allow End could allow the fatal termination of the application to be injected, yet End If is innocent.
If for any reason any token parse fails, the parse would will return false, which will in most areas of the system cause that code not to be complied in reflection. If for any reason rules are not working a expected, it is suggested to check the logs to look for any soft parse failures at ERROR level, as this can be a common cause of rules not working as desired.
Quotation Marks and Failing Closed
Two behaviours of the soft parse are worth knowing when a rule is refused for no apparent reason.
Quotation marks. Text between double quotes is taken out of the line before the token check, as an enclosed string may hold any character. In VB.net there is no backslash escape inside a string: only a doubled quote ("") writes a quote character, and the soft parse follows that rule. VB.net also reads the typographic double quotes U+201C (left), U+201D (right) and U+FF02 (fullwidth) as ordinary double quotes. Before the scan, the parser therefore replaces those three characters with the ASCII double quote, in the rule text that is scanned and in the text that is compiled, so that the scan and the compiler always see the same strings. A rule pasted from a word processor, with curly quotes, is read as if it had been written with straight quotes.
Failing closed. If anything goes wrong part way through the token scan (an unexpected exception, not merely an unknown token), the rule is refused. The parse returns false with the error “The rule text could not be parsed for restricted tokens and has been refused.” It is never read as “no restricted token was found”. The rule is then not compiled, as with any other parse failure, and the cause is logged at ERROR level.
SQL written by an author (Visualisation datasources, case search) is not passed through this token scan. It is checked against the PostgreSQL syntax tree instead: see Embed SQL Generate Grid in Datasource.
The premise of the Jube is that it is comprised of hundreds, if not thousands of rules, which are intended to match upon data processed in real-time. One of the reasons that the Jube is so fast in processing, despite the number of rules required of processing, is that when a rule is created, it is compiled to native code and as such runs about as fast as any low level .net programming function.
Compiling code dynamically is extraordinarily expensive and it is thunderously slow, hence cannot be relied upon in a real-time process. A process has been developed to perform compilation in the background while ensuring it can be referenced real-time as if it were - almost - a native function of the .Net platform, hence extraordinarily fast.
The Jube uses .Net reflection and the language is VB.net (as this is more intuitive than C#, although Jube is written in C#). The process of compilation is as follows:
- For every rule, a class is created that makes references to several third party DLL’s and;
- For the newly written class code, a function of sub routines is created and;
- The rules are invariably very small fragments that are intended to sit inside the newly created subroutine, as such the code is embedded.
- A check is made to see if the class code already exists, in a compiled state, in the compiled hash cache. This step ensures that there is no duplication in rules in the applications memory as if it already exists in a compiled state, it will simply be referenced rather than recompiled.
- In the absence of class code already existing in memory, it will be compiled to an assembly and;
- A delegate will be attached such that it provides recall performance not dissimilar to that of a native .Net function.
- Upon successful compilation, the assembly will be added to the compiled hash cache.
One of the legacy weaknesses of the .Net core when dealing with compiled code is that while assemblies can be compiled and loaded dynamically, they cannot be unloaded. It follows that a compiled assembly, even if not being used, will exist in the applications memory until the next restart. The compiled rules take up a negligible amount of space in memory, but it is worth bearing in mind as a explanation for shallow memory leak over a long period of time. In order to reduce the impact of this memory leak, a compiled hash cache is used to ensure that an assembly is only ever created the once in the lifetime of the application:
- When code is created dynamically, as described above, that code is hashed using MD5 to create a digest.
- This digest is the key to the assembly cache and upon successful compilation of the code into an assembly, that assembly is stored as the value of a dictionary entry.
- In all cases of dynamic compilation the compiled hash case will be referenced to see if the assembly already exists such to avoid expensive recompilation and memory leak.
Henceforth, in the use of the Assembly Cache, where rule criteria is often in common, the memory used by assemblies can often be reduced.
The following rules and scripts are subject to the compilation process and are the result of rules being created in the user interface as VB .Net code fragments:
- Abstraction Rules.
- Activation Rules.
- Gateway Rules.
- Inline Functions.
- Abstraction Calculations.
The following classes are created as much more advanced, and flexible, complete class stored in the database. The creation of these code fragments are documented separately, although it suffices at this stage to explain that code can be freestyle subject to it conforming to an interface specification.
- Inline Scripts which exist as an entire class, including Import statements, implementing a specific interface.
Any compilation errors will be written to the logs as ERROR level, detailing the compiler errors.
A rule that compiles can still raise an error when it runs, for example text that is not a number being converted to one. The engine wraps every rule in Try/Catch: the error is written to the logs at INFO level and the rule returns whatever it had set before the error. For a rule that had not yet set its result, that is False (not matched) for a Gateway, Abstraction, Activation or Reprocessing Rule, 0 for an Abstraction Calculation and Nothing for an Inline Function. A runtime error therefore looks like a rule that did not match; a backtest counts such errors separately (see Backtest).
Extensions
Extension methods enhance rule flexibility via a fluent syntax. For example, consider the expression:
If(Payload.StringValue.Contains("Value")) Then
Return Matched
End If
Here, Contains("Value") is an extension method with the signature Contains(this string) that returns a Boolean value.
Extension methods are developed in a dedicated assembly, namespace, and type: Jube.Dictionary.Extensions.Extensions.
During rule parsing and token fetching, the soft parser scans this type using reflection. Any identified methods are then added as rule tokens, making them available to use in rules, as they would otherwise be security restricted for use.
As a design principle, any advanced rule functionality in Jube is implemented via extension methods. A wide variety of extension methods are available for each of the data types implemented in Jube, with more added each release based on user feedback and new use cases.
The fluent syntax and the restriction of exposing functionality only via extension methods help maintain platform reliability. Extension methods are subject to some review and performance consideration, chiefly to ensure reliable realtime performance, noting that Do, While and For Looping is otherwise unavailable.
Curated Dynamic Expressions
Every extension method above is a real, compiled C# method, added by a Jube release. Administrators can also curate short, named expressions directly in the database (no release needed) for use exactly like any other extension method - e.g. Payload.Email.IsGmailEmail. This is off by default and layered on top of the token allowlist described above rather than around it - see Curated Dynamic Expressions for the full mechanism, the DictionaryEvalExpression schema, and how it stays safe. Curated names are entirely administrator-defined and optional - never assume any specific name, including the ones used as examples here, exists on a given instance without checking the live DictionaryEvalExpression table first.
The following extension methods are available:
| Method Signature | Description | Parameters |
|---|---|---|
| Boolean Extensions | ||
ToBinary(this bool @this) | Converts the boolean to a binary representation. | @this: The boolean to act on. |
ToString(this bool @this, string trueValue, string falseValue) | Returns a custom string based on the boolean value. | @this: The boolean to act on.trueValue: The value to return if true.falseValue: The value to return if false. |
| Char Extensions | ||
ConvertToUtf32(this char highSurrogate, char lowSurrogate) | Converts a UTF-16 surrogate pair into a Unicode code point. | highSurrogate: A high surrogate code unit (U+D800 through U+DBFF).lowSurrogate: A low surrogate code unit (U+DC00 through U+DFFF). |
GetNumericValue(this char c) | Gets the numeric value of a Unicode character. | c: The Unicode character to convert. |
GetUnicodeCategory(this char c) | Gets the Unicode category of a character. | c: The Unicode character to categorize. |
In(this char @this, params char[] values) | Checks if the character is equal to any in the provided array. | @this: The object to be compared.values: The value list to compare with the object. |
IsControl(this char c) | Checks if the character is a control character. | c: The Unicode character to evaluate. |
IsDigit(this char c) | Checks if the character is a decimal digit. | c: The Unicode character to evaluate. |
IsHighSurrogate(this char c) | Checks if the character is a high surrogate. | c: The Unicode character to evaluate. |
IsLetter(this char c) | Checks if the character is a Unicode letter. | c: The Unicode character to evaluate. |
IsLetterOrDigit(this char c) | Checks if the character is a letter or decimal digit. | c: The Unicode character to evaluate. |
IsLower(this char c) | Checks if the character is a lowercase letter. | c: The Unicode character to evaluate. |
IsLowSurrogate(this char c) | Checks if the character is a low surrogate. | c: The character to evaluate. |
IsNumber(this char c) | Checks if the character is a number. | c: The Unicode character to evaluate. |
IsPunctuation(this char c) | Checks if the character is a punctuation mark. | c: The Unicode character to evaluate. |
IsSeparator(this char c) | Checks if the character is a separator character. | c: The Unicode character to evaluate. |
IsSurrogate(this char c) | Checks if the character is a surrogate. | c: The Unicode character to evaluate. |
IsSurrogatePair(this char highSurrogate, char lowSurrogate) | Checks if two characters form a surrogate pair. | highSurrogate: The character to evaluate as high surrogate.lowSurrogate: The character to evaluate as low surrogate. |
IsSymbol(this char c) | Checks if the character is a symbol character. | c: The Unicode character to evaluate. |
IsUpper(this char c) | Checks if the character is an uppercase letter. | c: The Unicode character to evaluate. |
IsWhiteSpace(this char c) | Checks if the character is whitespace. | c: The Unicode character to evaluate. |
NotIn(this char @this, params char[] values) | Checks if the character is not equal to any in the provided array. | @this: The object to be compared.values: The value list to compare with the object. |
Repeat(this char @this, int repeatCount) | Repeats the character a specified number of times. | @this: The char to act on.repeatCount: Number of repeats. |
To(this char @this, char toCharacter) | Enumerates from the current character to the specified character. | @this: The char to act on.toCharacter: The target character. |
ToLower(this char c, CultureInfo culture) | Converts the character to lowercase using specified culture rules. | c: The Unicode character to convert.culture: An object that supplies culture-specific casing rules. |
ToLower(this char c) | Converts the character to lowercase. | c: The Unicode character to convert. |
ToLowerInvariant(this char c) | Converts the character to lowercase using invariant culture rules. | c: The Unicode character to convert. |
ToString(this char c) | Converts the character to its string representation. | c: The Unicode character to convert. |
ToUpper(this char c, CultureInfo culture) | Converts the character to uppercase using specified culture rules. | c: The Unicode character to convert.culture: An object that supplies culture-specific casing rules. |
ToUpper(this char c) | Converts the character to uppercase. | c: The Unicode character to convert. |
ToUpperInvariant(this char c) | Converts the character to uppercase using invariant culture rules. | c: The Unicode character to convert. |
| DateTime Extensions | ||
Age(this DateTime @this) | Calculates the age from the given date. | @this: The DateTime to act on. |
AgeInDays(this DateTime @this) | Returns the number of whole days since the date (negative if it is in the future). | @this: The DateTime to act on. |
Between(this DateTime @this, DateTime minValue, DateTime maxValue) | Checks if the date is between two dates (exclusive). | @this: The DateTime to act on.minValue: The minimum value.maxValue: The maximum value. |
BusinessDaysUntil(this DateTime @this, DateTime other) | Counts the weekdays (Mon-Fri) strictly after this date up to and including other – useful for settlement/SLA calculations. Negative when other is earlier. | @this: The DateTime to act on.other: The date to count towards. |
ConvertTime(this DateTime dateTime, TimeZoneInfo destinationTimeZone) | Converts the time to a different time zone. | dateTime: The date and time to convert.destinationTimeZone: The time zone to convert to. |
ConvertTime(this DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone) | Converts the time from one time zone to another. | dateTime: The date and time to convert.sourceTimeZone: The time zone of the dateTime.destinationTimeZone: The time zone to convert to. |
ConvertTimeBySystemTimeZoneId(this DateTime dateTime, string destinationTimeZoneId) | Converts the time using time zone identifiers. | dateTime: The date and time to convert.destinationTimeZoneId: The identifier of the destination time zone. |
ConvertTimeBySystemTimeZoneId(this DateTime dateTime, string sourceTimeZoneId, string destinationTimeZoneId) | Converts the time between time zones using identifiers. | dateTime: The date and time to convert.sourceTimeZoneId: The identifier of the source time zone.destinationTimeZoneId: The identifier of the destination time zone. |
ConvertTimeFromUtc(this DateTime dateTime, TimeZoneInfo destinationTimeZone) | Converts UTC time to a specified time zone. | dateTime: The Coordinated Universal Time (UTC).destinationTimeZone: The time zone to convert to. |
ConvertTimeToUtc(this DateTime dateTime) | Converts the time to UTC. | dateTime: The date and time to convert. |
ConvertTimeToUtc(this DateTime dateTime, TimeZoneInfo sourceTimeZone) | Converts the time from a specified time zone to UTC. | dateTime: The date and time to convert.sourceTimeZone: The time zone of the dateTime. |
Elapsed(this DateTime datetime) | Returns the time elapsed since the given date. | datetime: The datetime to act on. |
EndOfDay(this DateTime @this) | Returns the end of the day (23:59:59.999). | @this: The DateTime to act on. |
EndOfMonth(this DateTime @this) | Returns the end of the month. | @this: The DateTime to act on. |
EndOfWeek(this DateTime dt, DayOfWeek startDayOfWeek = DayOfWeek.Sunday) | Returns the end of the week. | dt: The DateTime to act on.startDayOfWeek: The start day of week (optional). |
EndOfYear(this DateTime @this) | Returns the end of the year. | @this: The DateTime to act on. |
FirstDayOfWeek(this DateTime @this) | Returns the first day of the week. | @this: The DateTime to act on. |
In(this DateTime @this, params DateTime[] values) | Checks if the date is equal to any in the provided array. | @this: The object to be compared.values: The value list to compare with the object. |
InRange(this DateTime @this, DateTime minValue, DateTime maxValue) | Checks if the date is between two dates (inclusive). | @this: The DateTime to act on.minValue: The minimum value.maxValue: The maximum value. |
IsAfternoon(this DateTime @this) | Checks if the time is in the afternoon. | @this: The DateTime to act on. |
IsDateEqual(this DateTime date, DateTime dateToCompare) | Checks if two dates have the same date part. | date: The date to act on.dateToCompare: The date to compare. |
IsDaylightSavingTime(this DateTime time, DaylightTime daylightTimes) | Checks if the date is within a daylight saving time period. | time: A date and time.daylightTimes: A daylight saving time period. |
IsFuture(this DateTime @this) | Checks if the date is in the future. | @this: The DateTime to act on. |
IsMorning(this DateTime @this) | Checks if the time is in the morning. | @this: The DateTime to act on. |
IsNow(this DateTime @this) | Checks if the date is the current moment. | @this: The DateTime to act on. |
IsoWeekOfYear(this DateTime @this) | Returns the ISO-8601 week number of the year. | @this: The DateTime to act on. |
IsPast(this DateTime @this) | Checks if the date is in the past. | @this: The DateTime to act on. |
IsTimeEqual(this DateTime time, DateTime timeToCompare) | Checks if two dates have the same time part. | time: The time to act on.timeToCompare: The time to compare. |
IsToday(this DateTime @this) | Checks if the date is today. | @this: The DateTime to act on. |
IsWeekDay(this DateTime @this) | Checks if the date is a weekday. | @this: The DateTime to act on. |
IsWeekendDay(this DateTime @this) | Checks if the date is a weekend day. | @this: The DateTime to act on. |
IsWithinBusinessHours(this DateTime @this, int startHour, int endHour) | Checks if the time falls within a given hour range (start inclusive, end exclusive). | @this: The DateTime to act on.startHour: The first hour (0-23) considered within business hours.endHour: The first hour (0-23) no longer considered within business hours. |
LastDayOfWeek(this DateTime @this) | Returns the last day of the week. | @this: The DateTime to act on. |
NotIn(this DateTime @this, params DateTime[] values) | Checks if the date is not equal to any in the provided array. | @this: The object to be compared.values: The value list to compare with the object. |
QuarterOfYear(this DateTime @this) | Returns the calendar quarter (1-4) the date falls in. | @this: The DateTime to act on. |
SetTime(this DateTime current, int hour) | Sets the time of the date (hour only). | current: The current date.hour: The hour. |
SetTime(this DateTime current, int hour, int minute) | Sets the time of the date (hour and minute). | current: The current date.hour: The hour.minute: The minute. |
SetTime(this DateTime current, int hour, int minute, int second) | Sets the time of the date (hour, minute, second). | current: The current date.hour: The hour.minute: The minute.second: The second. |
SetTime(this DateTime current, int hour, int minute, int second, int millisecond) | Sets the time of the date (hour, minute, second, millisecond). | current: The current date.hour: The hour.minute: The minute.second: The second.millisecond: The millisecond. |
StartOfDay(this DateTime @this) | Returns the start of the day (00:00:00.000). | @this: The DateTime to act on. |
StartOfMonth(this DateTime @this) | Returns the start of the month. | @this: The DateTime to act on. |
StartOfWeek(this DateTime dt, DayOfWeek startDayOfWeek = DayOfWeek.Sunday) | Returns the start of the week. | dt: The DateTime to act on.startDayOfWeek: The start day of week (optional). |
StartOfYear(this DateTime @this) | Returns the start of the year. | @this: The DateTime to act on. |
ToEpochTimeSpan(this DateTime @this) | Converts the date to an epoch time span. | @this: The DateTime to act on. |
ToFullDateTimeString(this DateTime @this) | Converts the date to a full date time string. | @this: The DateTime to act on. |
ToFullDateTimeString(this DateTime @this, string culture) | Converts the date to a full date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToFullDateTimeString(this DateTime @this, CultureInfo culture) | Converts the date to a full date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToLongDateShortTimeString(this DateTime @this) | Converts the date to a long date and short time string. | @this: The DateTime to act on. |
ToLongDateShortTimeString(this DateTime @this, string culture) | Converts the date to a long date and short time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToLongDateShortTimeString(this DateTime @this, CultureInfo culture) | Converts the date to a long date and short time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToLongDateString(this DateTime @this) | Converts the date to a long date string. | @this: The DateTime to act on. |
ToLongDateString(this DateTime @this, string culture) | Converts the date to a long date string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToLongDateString(this DateTime @this, CultureInfo culture) | Converts the date to a long date string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToLongDateTimeString(this DateTime @this) | Converts the date to a long date time string. | @this: The DateTime to act on. |
ToLongDateTimeString(this DateTime @this, string culture) | Converts the date to a long date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToLongDateTimeString(this DateTime @this, CultureInfo culture) | Converts the date to a long date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToLongTimeString(this DateTime @this) | Converts the date to a long time string. | @this: The DateTime to act on. |
ToLongTimeString(this DateTime @this, string culture) | Converts the date to a long time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToLongTimeString(this DateTime @this, CultureInfo culture) | Converts the date to a long time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToMonthDayString(this DateTime @this) | Converts the date to a month and day string. | @this: The DateTime to act on. |
ToMonthDayString(this DateTime @this, string culture) | Converts the date to a month and day string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToMonthDayString(this DateTime @this, CultureInfo culture) | Converts the date to a month and day string using a culture. | @this: The DateTime to act on.culture: The culture. |
Tomorrow(this DateTime @this) | Returns the next day at the same time. | @this: The DateTime to act on. |
ToRFC1123String(this DateTime @this) | Converts the date to an RFC1123 string. | @this: The DateTime to act on. |
ToRFC1123String(this DateTime @this, string culture) | Converts the date to an RFC1123 string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToRFC1123String(this DateTime @this, CultureInfo culture) | Converts the date to an RFC1123 string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToShortDateLongTimeString(this DateTime @this) | Converts the date to a short date and long time string. | @this: The DateTime to act on. |
ToShortDateLongTimeString(this DateTime @this, string culture) | Converts the date to a short date and long time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToShortDateLongTimeString(this DateTime @this, CultureInfo culture) | Converts the date to a short date and long time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToShortDateString(this DateTime @this) | Converts the date to a short date string. | @this: The DateTime to act on. |
ToShortDateString(this DateTime @this, string culture) | Converts the date to a short date string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToShortDateString(this DateTime @this, CultureInfo culture) | Converts the date to a short date string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToShortDateTimeString(this DateTime @this) | Converts the date to a short date time string. | @this: The DateTime to act on. |
ToShortDateTimeString(this DateTime @this, string culture) | Converts the date to a short date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToShortDateTimeString(this DateTime @this, CultureInfo culture) | Converts the date to a short date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToShortTimeString(this DateTime @this) | Converts the date to a short time string. | @this: The DateTime to act on. |
ToShortTimeString(this DateTime @this, string culture) | Converts the date to a short time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToShortTimeString(this DateTime @this, CultureInfo culture) | Converts the date to a short time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToSortableDateTimeString(this DateTime @this) | Converts the date to a sortable date time string. | @this: The DateTime to act on. |
ToSortableDateTimeString(this DateTime @this, string culture) | Converts the date to a sortable date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToSortableDateTimeString(this DateTime @this, CultureInfo culture) | Converts the date to a sortable date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToUniversalSortableDateTimeString(this DateTime @this) | Converts the date to a universal sortable date time string. | @this: The DateTime to act on. |
ToUniversalSortableDateTimeString(this DateTime @this, string culture) | Converts the date to a universal sortable date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToUniversalSortableDateTimeString(this DateTime @this, CultureInfo culture) | Converts the date to a universal sortable date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToUniversalSortableLongDateTimeString(this DateTime @this) | Converts the date to a universal sortable long date time string. | @this: The DateTime to act on. |
ToUniversalSortableLongDateTimeString(this DateTime @this, string culture) | Converts the date to a universal sortable long date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToUniversalSortableLongDateTimeString(this DateTime @this, CultureInfo culture) | Converts the date to a universal sortable long date time string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToYearMonthString(this DateTime @this) | Converts the date to a year and month string. | @this: The DateTime to act on. |
ToYearMonthString(this DateTime @this, string culture) | Converts the date to a year and month string using a culture. | @this: The DateTime to act on.culture: The culture. |
ToYearMonthString(this DateTime @this, CultureInfo culture) | Converts the date to a year and month string using a culture. | @this: The DateTime to act on.culture: The culture. |
Yesterday(this DateTime @this) | Returns the previous day at the same time. | @this: The DateTime to act on. |
| Double Extensions | ||
Abs(this double value) | Returns the absolute value. | value: A number that is greater than or equal to Double.MinValue, but less than or equal to Double.MaxValue. |
Acos(this double d) | Returns the angle whose cosine is the specified number. | d: A number representing a cosine, where d must be greater than or equal to -1, but less than or equal to 1. |
Asin(this double d) | Returns the angle whose sine is the specified number. | d: A number representing a sine, where d must be greater than or equal to -1, but less than or equal to 1. |
Atan(this double d) | Returns the angle whose tangent is the specified number. | d: A number representing a tangent. |
Atan2(this double y, double x) | Returns the angle whose tangent is the quotient of two numbers. | y: The y coordinate of a point.x: The x coordinate of a point. |
Between(this double @this, double minValue, double maxValue) | Checks if the value is between two values (exclusive). | @this: The double to act on.minValue: The minimum value.maxValue: The maximum value. |
Ceiling(this double a) | Returns the smallest integral value greater than or equal to the number. | a: A double-precision floating-point number. |
Clamp(this double @this, double minValue, double maxValue) | Restricts the value to lie within the given range. | @this: The double to act on.minValue: The minimum value.maxValue: The maximum value. |
Cos(this double d) | Returns the cosine of the specified angle. | d: An angle, measured in radians. |
Cosh(this double value) | Returns the hyperbolic cosine of the specified angle. | value: An angle, measured in radians. |
Exp(this double d) | Returns e raised to the specified power. | d: A number specifying a power. |
Floor(this double d) | Returns the largest integer less than or equal to the number. | d: A double-precision floating-point number. |
FromDays(this double value) | Returns a TimeSpan representing the number of days. | value: A number of days, accurate to the nearest millisecond. |
FromHours(this double value) | Returns a TimeSpan representing the number of hours. | value: A number of hours accurate to the nearest millisecond. |
FromMilliseconds(this double value) | Returns a TimeSpan representing the number of milliseconds. | value: A number of milliseconds. |
FromMinutes(this double value) | Returns a TimeSpan representing the number of minutes. | value: A number of minutes, accurate to the nearest millisecond. |
FromOADate(this double d) | Converts an OLE Automation date to a DateTime. | d: An OLE Automation Date value. |
FromSeconds(this double value) | Returns a TimeSpan representing the number of seconds. | value: A number of seconds, accurate to the nearest millisecond. |
HaversineDistanceKilometers(this double latitude1, double longitude1, double latitude2, double longitude2) | Returns the great-circle distance between two coordinates, in kilometers. Useful for geographic velocity / impossible-travel checks. | latitude1: Latitude of the first point.longitude1: Longitude of the first point.latitude2: Latitude of the second point.longitude2: Longitude of the second point. |
HaversineDistanceMiles(this double latitude1, double longitude1, double latitude2, double longitude2) | Returns the great-circle distance between two coordinates, in miles. | latitude1: Latitude of the first point.longitude1: Longitude of the first point.latitude2: Latitude of the second point.longitude2: Longitude of the second point. |
IEEERemainder(this double x, double y) | Returns the remainder from division. | x: A dividend.y: A divisor. |
ImpliedTravelSpeedKmh(this double latitude1, double longitude1, double latitude2, double longitude2, double hoursElapsed) | Returns the implied speed, in km/h, needed to travel between two coordinates in the given number of hours. Returns positive infinity when hoursElapsed is zero or negative, flagging simultaneous/backwards-in-time locations as impossible. | latitude1: Latitude of the first point.longitude1: Longitude of the first point.latitude2: Latitude of the second point.longitude2: Longitude of the second point.hoursElapsed: Hours elapsed between the two observations. |
In(this double @this, params double[] values) | Checks if the value is equal to any in the provided array. | @this: The object to be compared.values: The value list to compare with the object. |
InRange(this double @this, double minValue, double maxValue) | Checks if the value is between two values (inclusive). | @this: The double to act on.minValue: The minimum value.maxValue: The maximum value. |
IsInfinity(this double d) | Checks if the value is infinity. | d: A double-precision floating-point number. |
IsJustBelowThreshold(this double @this, double threshold, double marginPercent) | Checks if the value is below a threshold but within a percentage margin of it – a classic structuring/smurfing indicator. | @this: The amount to act on.threshold: The threshold (e.g. a reporting limit).marginPercent: The margin below the threshold, as a percentage of it. |
IsNaN(this double d) | Checks if the value is not a number. | d: A double-precision floating-point number. |
IsNegativeInfinity(this double d) | Checks if the value is negative infinity. | d: A double-precision floating-point number. |
IsPositiveInfinity(this double d) | Checks if the value is positive infinity. | d: A double-precision floating-point number. |
IsRoundAmount(this double @this, double nearest) | Checks if the value is an exact multiple of a given amount – e.g. a suspiciously round transaction amount. | @this: The amount to act on.nearest: The multiple to test against (e.g. 100 or 1000). |
IsWithinPercentOf(this double @this, double target, double percent) | Checks if the value is within a percentage tolerance of a target value (e.g. an invoice amount matching a purchase order). | @this: The value to act on.target: The value to compare against.percent: The allowed tolerance, as a percentage of target. |
IsWithinRadiusKm(this double latitude1, double longitude1, double latitude2, double longitude2, double radiusKm) | Checks if two coordinates are within a given distance of each other, in kilometers – a geofence check. | latitude1: Latitude of the first point.longitude1: Longitude of the first point.latitude2: Latitude of the second point.longitude2: Longitude of the second point.radiusKm: The radius to test against. |
LeadingSignificantDigit(this double @this) | Returns the first non-zero digit of the value, ignoring sign and magnitude – the input to a Benford’s Law check. Zero, infinity and NaN give 0. | @this: The value to act on. |
Lerp(this double @this, double end, double amount) | Linearly interpolates between this value and end. | @this: The start value.end: The end value.amount: The interpolation amount, typically 0 to 1. |
Log(this double d) | Returns the natural logarithm. | d: The number whose logarithm is to be found. |
Log(this double d, double newBase) | Returns the logarithm in a specified base. | d: The number whose logarithm is to be found.newBase: The base of the logarithm. |
Log10(this double d) | Returns the base 10 logarithm. | d: A number whose logarithm is to be found. |
Max(this double val1, double val2) | Returns the larger of two numbers. | val1: The first of two double-precision floating-point numbers to compare.val2: The second of two double-precision floating-point numbers to compare. |
Min(this double val1, double val2) | Returns the smaller of two numbers. | val1: The first of two double-precision floating-point numbers to compare.val2: The second of two double-precision floating-point numbers to compare. |
NotIn(this double @this, params double[] values) | Checks if the value is not equal to any in the provided array. | @this: The object to be compared.values: The value list to compare with the object. |
PercentageChangeFrom(this double @this, double previousValue) | Returns the percentage change from a previous value to this value. | @this: The current value.previousValue: The value to compare against. |
Pow(this double x, double y) | Returns a number raised to a specified power. | x: A double-precision floating-point number to be raised to a power.y: A double-precision floating-point number that specifies a power. |
Round(this double a) | Rounds to the nearest integral value. | a: A double-precision floating-point number to be rounded. |
Round(this double a, MidpointRounding mode) | Rounds using specified rounding rules. | a: A double-precision floating-point number to be rounded.mode: Specification for how to round if it is midway between two other numbers. |
Round(this double a, int digits) | Rounds to a specified number of fractional digits. | a: A double-precision floating-point number to be rounded.digits: The number of fractional digits in the return value. |
Round(this double a, int digits, MidpointRounding mode) | Rounds to specified digits using rounding rules. | a: A double-precision floating-point number to be rounded.digits: The number of fractional digits in the return value.mode: Specification for how to round if it is midway between two other numbers. |
Sign(this double value) | Returns the sign of the number. | value: A signed number. |
Sin(this double a) | Returns the sine of the specified angle. | a: An angle, measured in radians. |
Sinh(this double value) | Returns the hyperbolic sine of the specified angle. | value: An angle, measured in radians. |
Sqrt(this double d) | Returns the square root. | d: The number whose square root is to be found. |
Tan(this double a) | Returns the tangent of the specified angle. | a: An angle, measured in radians. |
Tanh(this double value) | Returns the hyperbolic tangent of the specified angle. | value: An angle, measured in radians. |
ToMoney(this double @this) | Converts the number to a money format. | @this: The double to act on. |
Truncate(this double d) | Calculates the integral part of the number. | d: A number to truncate. |
ZScore(this double @this, double mean, double standardDeviation) | Returns the number of standard deviations this value is from the mean. | @this: The value to act on.mean: The mean of the population.standardDeviation: The standard deviation of the population. |
RatioOf, PercentOf, Complement, SumWith, MaxWith and 32 more calculation methods | Return a number, NaN when undefined, each also with Above/Below/InRange/OutsideRange comparisons. Listed in full in the Rule Pipeline Reference. | |
| Int32 Extensions | ||
Abs(this int value) | Returns the absolute value. | value: A number that is greater than Int32.MinValue, but less than or equal to Int32.MaxValue. |
Between(this int @this, int minValue, int maxValue) | Checks if the value is between two values (exclusive). | @this: The int to act on.minValue: The minimum value.maxValue: The maximum value. |
BigMul(this int a, int b) | Produces the full product of two numbers. | a: The first number to multiply.b: The second number to multiply. |
ConvertFromUtf32(this int utf32) | Converts a Unicode code point to a UTF-16 string. | utf32: A 21-bit Unicode code point. |
Days(this int @this) | Returns a TimeSpan representing the number of days. | @this: The int to act on. |
DaysInMonth(this int year, int month) | Returns the number of days in the specified month and year. | year: The year.month: The month (a number ranging from 1 to 12). |
DigitSum(this int @this) | Returns the sum of the absolute value’s decimal digits. | @this: The int to act on. |
DivRem(this int a, int b, out int result) | Divides and returns the quotient and remainder. | a: The dividend.b: The divisor.result: The remainder. |
FactorOf(this int @this, int factorNumer) | Checks if the number is a factor of another. | @this: The int to act on.factorNumer: The number to check against. |
FromArgb(this int argb) | Creates a Color from a 32-bit ARGB value. | argb: A value specifying the 32-bit ARGB value. |
FromArgb(this int argb, int red, int green, int blue) | Creates a Color from ARGB components. | argb: The alpha component.red: The red component (0-255).green: The green component (0-255).blue: The blue component (0-255). |
FromArgb(this int argb, Color baseColor) | Creates a Color with a new alpha value. | argb: The alpha value for the new Color.baseColor: The Color from which to create the new Color. |
FromArgb(this int argb, int green, int blue) | Creates a Color from RGB components (alpha implicit). | argb: The red component.green: The green component (0-255).blue: The blue component (0-255). |
FromOle(this int oleColor) | Converts an OLE color to a Color. | oleColor: The OLE color to translate. |
FromWin32(this int win32Color) | Converts a Windows color to a Color. | win32Color: The Windows color to translate. |
GetBytes(this int value) | Returns the value as a byte array. | value: The number to convert. |
GreatestCommonDivisor(this int @this, int other) | Returns the greatest common divisor of the two values. | @this: The int to act on.other: The other value. |
HostToNetworkOrder(this int host) | Converts from host byte order to network byte order. | host: The number to convert, expressed in host byte order. |
Hours(this int @this) | Returns a TimeSpan representing the number of hours. | @this: The int to act on. |
In(this int @this, params int[] values) | Checks if the value is equal to any in the provided array. | @this: The object to be compared.values: The value list to compare with the object. |
InRange(this int @this, int minValue, int maxValue) | Checks if the value is between two values (inclusive). | @this: The int to act on.minValue: The minimum value.maxValue: The maximum value. |
IsEven(this int @this) | Checks if the number is even. | @this: The int to act on. |
IsLeapYear(this int year) | Checks if the year is a leap year. | year: A 4-digit year. |
IsMultipleOf(this int @this, int factor) | Checks if the number is a multiple of another. | @this: The int to act on.factor: The factor to check against. |
IsOdd(this int @this) | Checks if the number is odd. | @this: The int to act on. |
IsPrime(this int @this) | Checks if the number is prime. | @this: The int to act on. |
LeastCommonMultiple(this int @this, int other) | Returns the least common multiple of the two values. | @this: The int to act on.other: The other value. |
Max(this int val1, int val2) | Returns the larger of two numbers. | val1: The first of two 32-bit signed integers to compare.val2: The second of two 32-bit signed integers to compare. |
Milliseconds(this int @this) | Returns a TimeSpan representing the number of milliseconds. | @this: The int to act on. |
Min(this int val1, int val2) | Returns the smaller of two numbers. | val1: The first of two 32-bit signed integers to compare.val2: The second of two 32-bit signed integers to compare. |
Minutes(this int @this) | Returns a TimeSpan representing the number of minutes. | @this: The int to act on. |
NetworkToHostOrder(this int network) | Converts from network byte order to host byte order. | network: The number to convert, expressed in network byte order. |
NotIn(this int @this, params int[] values) | Checks if the value is not equal to any in the provided array. | @this: The object to be compared.values: The value list to compare with the object. |
Seconds(this int @this) | Returns a TimeSpan representing the number of seconds. | @this: The int to act on. |
Sign(this int value) | Returns the sign of the number. | value: A signed number. |
Weeks(this int @this) | Returns a TimeSpan representing the number of weeks. | @this: The int to act on. |
| String Extensions | ||
Br2Nl(this string @this) | Converts line breaks to newlines. | @this: The string to act on. |
CardNetwork(this string @this) | Classifies a card number by its IIN/BIN prefix (Visa, Mastercard, AmericanExpress, Discover, DinersClub, Jcb, or Unknown). | @this: The digits-only card number to act on. |
CompareOrdinal(this string strA, int indexA, string strB, int indexB, int length) | Compares substrings using ordinal rules. | strA: The first string to use in the comparison.indexA: The starting index of the substring in strA.strB: The second string to use in the comparison.indexB: The starting index of the substring in strB.length: The maximum number of characters in the substrings to compare. |
CompareOrdinal(this string strA, string strB) | Compares two strings using ordinal rules. | strA: The first string to compare.strB: The second string to compare. |
Concat(this string str0, string str1) | Concatenates two strings. | str0: The first string to concatenate.str1: The second string to concatenate. |
Concat(this string str0, string str1, string str2) | Concatenates three strings. | str0: The first string to concatenate.str1: The second string to concatenate.str2: The third string to concatenate. |
Concat(this string str0, string str1, string str2, string str3) | Concatenates four strings. | str0: The first string to concatenate.str1: The second string to concatenate.str2: The third string to concatenate.str3: The fourth string to concatenate. |
Concatenate(this IEnumerable<string> @this) | Concatenates a collection of strings. | @this: The string collection to act on. |
Concatenate<T>(this IEnumerable<T> source, Func<T, string> func) | Concatenates a collection using a selector function. | source: The source collection to act on.func: The function to extract strings from elements. |
ConcatWith(this string @this, params string[] values) | Concatenates the string with others. | @this: The string to act on.values: The strings to concatenate with. |
Contains(this string @this, string value) | Checks if the string contains a substring. | @this: The string to act on.value: The substring to search for. |
Contains(this string @this, string value, StringComparison comparisonType) | Checks if the string contains a substring with comparison rules. | @this: The string to act on.value: The substring to search for.comparisonType: The type of comparison to use. |
ContainsAll(this string @this, StringComparison comparisonType, params string[] values) | Checks if the string contains all substrings with comparison rules. | @this: The string to act on.comparisonType: The type of comparison to use.values: The substrings to search for. |
ContainsAll(this string @this, params string[] values) | Checks if the string contains all specified substrings. | @this: The string to act on.values: The substrings to search for. |
ContainsAny(this string @this, StringComparison comparisonType, params string[] values) | Checks if the string contains any substrings with comparison rules. | @this: The string to act on.comparisonType: The type of comparison to use.values: The substrings to search for. |
ContainsAny(this string @this, params string[] values) | Checks if the string contains any of the specified substrings. | @this: The string to act on.values: The substrings to search for. |
ConvertToUtf32(this string s, int index) | Converts a character or surrogate pair to a Unicode code point. | s: A string that contains a character or surrogate pair.index: The index position of the character or surrogate pair. |
DecodeBase64(this string @this) | Decodes Base64 to UTF-8 text. | @this: The Base64 string to decode. |
DeserializeJson<T>(this string json) | Deserializes a JSON string to an object. | json: The JSON string to deserialize. |
DeserializeJson<T>(this string json, Encoding encoding) | Deserializes a JSON string using specified encoding. | json: The JSON string to deserialize.encoding: The text encoding to use. |
DigitCount(this string @this) | Counts the digit characters in the string. | @this: The string to act on. |
EmailDomain(this string @this) | Returns everything after the “@” in an email address, or an empty string if there is none. | @this: The string to act on. |
EmailLocalPart(this string @this) | Returns everything before the “@” in an email address, or the whole string if there is none. | @this: The string to act on. |
EncodeBase64(this string @this) | Encodes the UTF-8 bytes of a string as Base64 (ASCII text encodes exactly as before). | @this: The string to encode. |
EqualsIgnoreCase(this string @this, string comparedString) | Checks if two strings are equal ignoring case. | @this: The string to act on.comparedString: The string to compare with. |
EscapeXml(this string @this) | Escapes XML special characters. | @this: The string to act on. |
Extract(this string @this, Func<char, bool> predicate) | Extracts characters based on a predicate. | @this: The string to act on.predicate: The function to determine which characters to extract. |
ExtractDecimal(this string @this) | Extracts a decimal number from the string. | @this: The string to act on. |
ExtractDouble(this string @this) | Extracts a double from the string, reading . as the decimal point whatever the server culture. | @this: The string to act on. |
ExtractInt16(this string @this) | Extracts an Int16 from the string. | @this: The string to act on. |
ExtractInt32(this string @this) | Extracts an Int32 from the string. | @this: The string to act on. |
ExtractInt64(this string @this) | Extracts an Int64 from the string. | @this: The string to act on. |
ExtractLetter(this string @this) | Extracts letters from the string. | @this: The string to act on. |
ExtractManyDecimal(this string @this) | Extracts all decimal numbers from the string. | @this: The string to act on. |
ExtractManyDouble(this string @this) | Extracts all doubles from the string, reading . as the decimal point whatever the server culture. | @this: The string to act on. |
ExtractManyInt16(this string @this) | Extracts all Int16 from the string. | @this: The string to act on. |
ExtractManyInt32(this string @this) | Extracts all Int32 from the string. | @this: The string to act on. |
ExtractManyInt64(this string @this) | Extracts all Int64 from the string. | @this: The string to act on. |
ExtractManyUInt16(this string @this) | Extracts all UInt16 from the string. | @this: The string to act on. |
ExtractManyUInt32(this string @this) | Extracts all UInt32 from the string. | @this: The string to act on. |
ExtractManyUInt64(this string @this) | Extracts all UInt64 from the string. | @this: The string to act on. |
ExtractNumber(this string @this) | Extracts numbers from the string. | @this: The string to act on. |
ExtractUInt16(this string @this) | Extracts a UInt16 from the string. | @this: The string to act on. |
ExtractUInt32(this string @this) | Extracts a UInt32 from the string. | @this: The string to act on. |
ExtractUInt64(this string @this) | Extracts a UInt64 from the string. | @this: The string to act on. |
Format(this string format, object arg0) | Replaces format items in a string. | format: A composite format string.arg0: The object to format. |
Format(this string format, object arg0, object arg1) | Replaces format items with two objects. | format: A composite format string.arg0: The first object to format.arg1: The second object to format. |
Format(this string format, object arg0, object arg1, object arg2) | Replaces format items with three objects. | format: A composite format string.arg0: The first object to format.arg1: The second object to format.arg2: The third object to format. |
Format(this string format, params object[] args) | Replaces format items with an array of objects. | format: A composite format string.args: An object array that contains zero or more objects to format. |
FormatWith(this string @this, object arg0) | Replaces format items with a single object. | @this: A String containing zero or more format items.arg0: The argument to format. |
FormatWith(this string @this, object arg0, object arg1) | Replaces format items with two objects. | @this: A String containing zero or more format items.arg0: The first argument to format.arg1: The second argument to format. |
FormatWith(this string @this, object arg0, object arg1, object arg2) | Replaces format items with three objects. | @this: A String containing zero or more format items.arg0: The first argument to format.arg1: The second argument to format.arg2: The third argument to format. |
FormatWith(this string @this, params object[] values) | Replaces format items with an array of objects. | @this: A String containing zero or more format items.values: An Object array containing zero or more objects to format. |
GetAfter(this string @this, string value) | Gets the substring after the specified value. | @this: The string to act on.value: The value to search for. |
GetBefore(this string @this, string value) | Gets the substring before the specified value. | @this: The string to act on.value: The value to search for. |
GetBetween(this string @this, string before, string after) | Gets the substring between two specified values. | @this: The string to act on.before: The string before to search.after: The string after to search. |
GetNumericValue(this string s, int index) | Gets the numeric value of a character at a position. | s: A string.index: The character position in the string. |
GetUnicodeCategory(this string s, int index) | Gets the Unicode category of a character at a position. | s: A string.index: The character position in the string. |
HasSequentialDigits(this string @this, int minRunLength) | Checks if the string contains an ascending or descending run of digits at least this long (e.g. “123456”) – a synthetic/weak-data indicator. | @this: The string to act on.minRunLength: The minimum run length to flag (clamped to at least 2). |
HtmlAttributeEncode(this string s) | HTML attribute encodes a string. | s: The string to encode. |
HtmlDecode(this string s) | HTML decodes a string. | s: The string to decode. |
HtmlEncode(this string s) | HTML encodes a string. | s: The string to encode. |
IfEmpty(this string value, string defaultValue) | Returns a default value if the string is empty. | value: The string to check.defaultValue: The default value to return if empty. |
In(this string @this, params string[] values) | Checks if the string is equal to any in the provided array. | @this: The object to be compared.values: The value list to compare with the object. |
InitialsOf(this string @this) | Returns the uppercased first letter of each whitespace-separated word. | @this: The string to act on. |
Intern(this string str) | Retrieves the system’s reference to the string. | str: A string to search for in the intern pool. |
IsAllSameCharacter(this string @this) | Checks if every character in the string is the same (e.g. “1111111”). | @this: The string to act on. |
IsAlpha(this string @this) | Checks if the string contains only letters. | @this: The string to act on. |
IsAlphaNumeric(this string @this) | Checks if the string contains only letters and numbers. | @this: The string to act on. |
IsAnagram(this string @this, string otherString) | Checks if the string is an anagram of another. | @this: The string to act on.otherString: The other string to compare with. |
IsControl(this string s, int index) | Checks if a character at a position is a control character. | s: A string.index: The position of the character to evaluate. |
IsDigit(this string s, int index) | Checks if a character at a position is a digit. | s: A string.index: The position of the character to evaluate. |
IsEmpty(this string @this) | Checks if the string is empty. | @this: The string to act on. |
IsHighSurrogate(this string s, int index) | Checks if a character at a position is a high surrogate. | s: A string.index: The position of the character to evaluate. |
IsInterned(this string str) | Retrieves a reference to the string from the intern pool. | str: The string to search for in the intern pool. |
IsLetter(this string s, int index) | Checks if a character at a position is a letter. | s: A string.index: The position of the character to evaluate. |
IsLetterOrDigit(this string s, int index) | Checks if a character at a position is a letter or digit. | s: A string.index: The position of the character to evaluate. |
IsLike(this string @this, string pattern) | Checks if the string matches a pattern with wildcards; matching is limited to 250 ms. | @this: The string to act on.pattern: The pattern to use. Use ‘*’ as wildcard string. |
IsLower(this string s, int index) | Checks if a character at a position is lowercase. | s: A string.index: The position of the character to evaluate. |
IsLowSurrogate(this string s, int index) | Checks if a character at a position is a low surrogate. | s: A string.index: The position of the character to evaluate. |
IsMatch(this string input, string pattern) | Checks if the string matches a regular expression; matching is limited to 250 ms. | input: The string to search for a match.pattern: The regular expression pattern to match. |
IsMatch(this string input, string pattern, RegexOptions options) | Checks if the string matches a regex with options; matching is limited to 250 ms. | input: The string to search for a match.pattern: The regular expression pattern to match.options: A bitwise combination of the enumeration values that provide options for matching. |
IsNotEmpty(this string @this) | Checks if the string is not empty. | @this: The string to act on. |
IsNotNull(this string @this) | Checks if the string is not null. | @this: The string to act on. |
IsNotNullOrEmpty(this string @this) | Checks if the string is not null or empty. | @this: The string to act on. |
IsNotNullOrWhiteSpace(this string value) | Checks if the string is not null, empty, or whitespace. | value: The string to test. |
IsNull(this string @this) | Checks if the string is null. | @this: The string to act on. |
IsNullOrEmpty(this string @this) | Checks if the string is null or empty. | @this: The string to act on. |
IsNullOrWhiteSpace(this string value) | Checks if the string is null, empty, or whitespace. | value: The string to test. |
IsNumber(this string s, int index) | Checks if a character at a position is a number. | s: A string.index: The position of the character to evaluate. |
IsNumeric(this string @this) | Checks if the string contains only numbers. | @this: The string to act on. |
IsPalindrome(this string @this) | Checks if the string is a palindrome. | @this: The string to act on. |
IsPunctuation(this string s, int index) | Checks if a character at a position is punctuation. | s: A string.index: The position of the character to evaluate. |
IsSeparator(this string s, int index) | Checks if a character at a position is a separator. | s: A string.index: The position of the character to evaluate. |
IsSurrogate(this string s, int index) | Checks if a character at a position is a surrogate. | s: A string.index: The position of the character to evaluate. |
IsSurrogatePair(this string s, int index) | Checks if two characters form a surrogate pair. | s: A string.index: The starting position of the pair of characters to evaluate. |
IsSymbol(this string s, int index) | Checks if a character at a position is a symbol. | s: A string.index: The position of the character to evaluate. |
IsUpper(this string s, int index) | Checks if a character at a position is uppercase. | s: A string.index: The position of the character to evaluate. |
IsValidBic(this string @this) | Checks if the string is a well-formed 8 or 11 character SWIFT/BIC code. | @this: The string to act on. Case-insensitive. |
IsValidCardExpiry(this string @this) | Checks if the string is a MM/YY or MM/YYYY card expiry that has not yet elapsed. | @this: The string to act on. |
IsValidEmail(this string obj) | Checks if the string is a valid email address, including plus-addressed local parts such as ann+tag@example.com. | obj: The string to act on. |
IsValidIban(this string @this) | Checks if the string is a well-formed IBAN with a valid mod-97 checksum. | @this: The string to act on. Spaces are ignored; case-insensitive. |
IsValidIP(this string obj) | Checks if the string is a valid IP address. | obj: The string to act on. |
IsValidLuhn(this string @this) | Checks if the string is a numeric string with a valid Luhn checksum digit – validates card numbers, IMEI numbers, etc. | @this: The string to act on. Must be digits only. |
IsWhiteSpace(this string s, int index) | Checks if a character at a position is whitespace. | s: A string.index: The position of the character to evaluate. |
JaroWinklerSimilarity(this string @this, string other) | Returns a 0-1 similarity score that favours strings sharing a common prefix – standard for fuzzy name matching in sanctions/AML screening. | @this: The string to act on.other: The string to compare with. |
JavaScriptStringEncode(this string value) | JavaScript encodes a string. | value: A string to encode. |
JavaScriptStringEncode(this string value, bool addDoubleQuotes) | JavaScript encodes with optional double quotes. | value: A string to encode.addDoubleQuotes: A value that indicates whether double quotation marks will be included around the encoded string. |
Join(this string separator, IEnumerable<string> values) | Joins a string collection with a separator. | separator: The string to use as a separator.values: An array that contains the elements to concatenate. |
Join(this string separator, params object[] values) | Joins an array of objects with a separator. | separator: The string to use as a separator.values: An array that contains the elements to concatenate. |
Join(this string separator, params string[] value) | Joins an array of strings with a separator. | separator: The string to use as a separator.value: An array that contains the elements to concatenate. |
Join(this string separator, string[] value, int startIndex, int count) | Joins a subset of an array with a separator. | separator: The string to use as a separator.value: An array that contains the elements to concatenate.startIndex: The first element in value to use.count: The number of elements of value to use. |
Join<T>(this string separator, IEnumerable<T> values) | Joins a collection with a separator. | separator: The string to use as a separator.values: An array that contains the elements to concatenate. |
Left(this string @this, int length) | Gets the left part of the string. | @this: The string to act on.length: The length of the left part to get. |
LeftSafe(this string @this, int length) | Safely gets the left part (handles out-of-range). | @this: The string to act on.length: The length of the left part to get. |
LetterCount(this string @this) | Counts the letter characters in the string. | @this: The string to act on. |
LevenshteinDistance(this string @this, string other) | Returns the edit distance (insertions, deletions, substitutions) between two strings. | @this: The string to act on.other: The string to compare with. |
MaskExceptLast(this string @this, int visibleCount, char mask = '*') | Masks every character except the trailing visibleCount – for displaying account/card numbers safely. | @this: The string to act on.visibleCount: Number of trailing characters to leave visible.mask: The mask character. |
Match(this string input, string pattern) | Searches for the first regex match; matching is limited to 250 ms. | input: The string to search for a match.pattern: The regular expression pattern to match. |
Match(this string input, string pattern, RegexOptions options) | Searches for the first regex match with options; matching is limited to 250 ms. | input: The string to search for a match.pattern: The regular expression pattern to match.options: A bitwise combination of the enumeration values that provide options for matching. |
Matches(this string input, string pattern) | Searches for all regex matches; matching is limited to 250 ms. | input: The string to search for a match.pattern: The regular expression pattern to match. |
Matches(this string input, string pattern, RegexOptions options) | Searches for all regex matches with options; matching is limited to 250 ms. | input: The string to search for a match.pattern: The regular expression pattern to match.options: A bitwise combination of the enumeration values that specify options for matching. |
Nl2Br(this string @this) | Converts newlines to line breaks. | @this: The string to act on. |
NormalizeEmailAlias(this string @this) | Lowercases an email address and strips any “+tag” alias from the local part – links accounts that abuse plus-addressing for multi-accounting. | @this: The string to act on. |
NotIn(this string @this, params string[] values) | Checks if the string is not equal to any in the provided array. | @this: The object to be compared.values: The value list to compare with the object. |
NullIfEmpty(this string value) | Returns null if the string is null or empty. | value: The string to check. |
ParseQueryString(this string query) | Parses a query string into a NameValueCollection. | query: The query string to parse. |
ParseQueryString(this string query, Encoding encoding) | Parses a query string with specified encoding. | query: The query string to parse.encoding: The encoding to use. |
RemoveDiacritics(this string @this) | Removes diacritics from the string. | @this: The string to act on. |
RemoveLetter(this string @this) | Removes letters from the string. | @this: The string to act on. |
RemoveNumber(this string @this) | Removes numbers from the string. | @this: The string to act on. |
RemoveWhere(this string @this, Func<char, bool> predicate) | Removes characters based on a predicate. | @this: The string to act on.predicate: The function to determine which characters to remove. |
Repeat(this string @this, int repeatCount) | Repeats the string a specified number of times. | @this: The string to act on.repeatCount: Number of repeats. |
Replace(this string @this, int startIndex, int length, string value) | Replaces a substring at a specific position. | @this: The string to act on.startIndex: The start index.length: The length.value: The replacement value. |
ReplaceByEmpty(this string @this, params string[] values) | Replaces specified values with an empty string. | @this: The string to act on.values: The values to replace. |
ReplaceFirst(this string @this, int number, string oldValue, string newValue) | Replaces the first N occurrences of a substring. | @this: The string to act on.number: The number of occurrences to replace.oldValue: The value to replace.newValue: The replacement value. |
ReplaceFirst(this string @this, string oldValue, string newValue) | Replaces the first occurrence of a substring. | @this: The string to act on.oldValue: The value to replace.newValue: The replacement value. |
ReplaceLast(this string @this, int number, string oldValue, string newValue) | Replaces the last N occurrences of a substring. | @this: The string to act on.number: The number of occurrences to replace.oldValue: The value to replace.newValue: The replacement value. |
ReplaceLast(this string @this, string oldValue, string newValue) | Replaces the last occurrence of a substring. | @this: The string to act on.oldValue: The value to replace.newValue: The replacement value. |
ReplaceWhenEquals(this string @this, string oldValue, string newValue) | Replaces the string if it equals a value. | @this: The string to act on.oldValue: The value to compare with.newValue: The replacement value. |
Reverse(this string @this) | Reverses the string. | @this: The string to act on. |
Right(this string @this, int length) | Gets the right part of the string. | @this: The string to act on.length: The length of the right part to get. |
RightSafe(this string @this, int length) | Safely gets the right part (handles out-of-range). | @this: The string to act on.length: The length of the right part to get. |
ShannonEntropy(this string @this) | Returns the Shannon entropy of the string, in bits per character – a measure of randomness (e.g. detecting algorithmically generated identifiers). | @this: The string to act on. |
SimilarityTo(this string @this, string other) | Returns a 0-1 similarity score derived from the normalized Levenshtein distance. | @this: The string to act on.other: The string to compare with. |
Soundex(this string @this) | Returns the four-character American Soundex phonetic code, for matching similar-sounding names. | @this: The string to act on. |
Split(this string @this, string separator, StringSplitOptions option = StringSplitOptions.None) | Splits the string using a separator. | @this: The string to act on.separator: A string that delimit the substrings in this string.option: Specify RemoveEmptyEntries to omit empty array elements, or None to include empty array elements. |
ToByteArray(this string @this) | Converts the string to a byte array. | @this: The string to act on. |
ToEnum<T>(this string @this) | Converts the string to an enum value. | @this: The string to act on. |
ToTitleCase(this string @this) | Converts the string to title case. | @this: The string to act on. |
ToTitleCase(this string @this, CultureInfo cultureInfo) | Converts to title case using specified culture. | @this: The string to act on.cultureInfo: Information describing the culture. |
ToValidDateTimeOrNull(this string @this) | Converts to a valid DateTime or null. | @this: The string to act on. |
ToXDocument(this string @this) | Converts the string to an XDocument. | @this: The string to act on. |
ToXmlDocument(this string @this) | Converts the string to an XmlDocument. | @this: The string to act on. |
Truncate(this string @this, int maxLength) | Truncates the string to a maximum length. | @this: The string to act on.maxLength: The maximum length. |
Truncate(this string @this, int maxLength, string suffix) | Truncates with a suffix. | @this: The string to act on.maxLength: The maximum length.suffix: The suffix to append when truncated. |
UrlDecode(this string str) | URL decodes a string. | str: The string to decode. |
UrlDecode(this string str, Encoding e) | URL decodes with specified encoding. | str: The string to decode.e: The encoding that specifies the decoding scheme. |
UrlDecodeToBytes(this string str) | URL decodes to a byte array. | str: The string to decode. |
UrlDecodeToBytes(this string str, Encoding e) | URL decodes to a byte array with encoding. | str: The string to decode.e: The encoding object that specifies the decoding scheme. |
UrlEncode(this string str) | URL encodes a string. | str: The text to encode. |
UrlEncode(this string str, Encoding e) | URL encodes with specified encoding. | str: The text to encode.e: The encoding object that specifies the encoding scheme. |
UrlEncodeToBytes(this string str) | URL encodes to a byte array. | str: The string to encode. |
UrlEncodeToBytes(this string str, Encoding e) | URL encodes to a byte array with encoding. | str: The string to encode.e: The encoding that specifies the encoding scheme. |
UrlPathEncode(this string str) | URL path encodes a string. | str: The text to encode. |
IsSomehowInList, IsSomehowLike, ContainsSomehowInList, FuzzyBestScore and the per-algorithm Is...InList fuzzy matchers | Fuzzy membership and comparison against a List token or a single value. The options string and every algorithm are in the Rule Pipeline Reference. | |
| Nullable Extensions | ||
OrNaN(this double? @this) | Reads a nullable number, NaN when it is null or not finite. For an HTTP Adaptation, HttpAdaptation.Name.Value.OrNaN(). | |
OrZero(this double? @this) | Reads a nullable number, zero when it is null or not finite. Use it only where a missing value should read as zero. | |
| Pipeline Extensions | ||
Start(this double, int, string, DateTime or bool @this) | Optional. Begins a pipeline explicitly. Every typed test step called on a plain value begins one itself. | |
Start<T>(this Flow<T> @this) | Returns the pipeline unchanged, so an explicit Start() is harmless to repeat. | |
Against<T, TNext>(this Flow<T> @this, TNext value) | Switches to testing another value, keeping the outcome, score and label. | |
Match / Reject / Break<T>(this Flow<T> @this) | Decide unconditionally, if not already decided. | |
Fail<T>(this Flow<T> @this, string label) | Decide errored, with a reason. | |
OtherwiseMatch / OtherwiseReject<T>(this Flow<T> @this) | Decide only if nothing has decided yet. | |
Reset<T>(this Flow<T> @this) | Return to undecided and clear the score and label. | |
Label<T>(this Flow<T> @this, string label) | Attach a reason carried to the decision. | |
MatchWhen / RejectWhen / BreakWhen / RequireThat / EnsureThat<T>(this Flow<T> @this, bool condition) | Apply any Boolean expression, including any other extension method, as a pipeline step. | |
AddScore / AddScoreWhen / CapScore<T>(this Flow<T> @this, ...) | Accumulate a score across steps. | |
MatchIfScoreAtLeast / BreakIfScoreAtLeast / RejectIfScoreBelow / RequireScoreAtLeast<T>(this Flow<T> @this, double threshold) | Decide from the accumulated score. | |
IsMatched / IsRejected / IsBroken / IsUndecided / IsErrored<T>(this Flow<T> @this) | Read the outcome as a Boolean. | |
ToBoolean<T>(this Flow<T> @this) | The Boolean a pipeline converts to. True only when it decided matched. | |
ToScore<T>(this Flow<T> @this) | The accumulated score. | |
ToNumber(this Flow<double> or Flow<int> @this) | The value as a plain number, NaN if the pipeline errored. | |
ParseDouble / ParseInteger / ParseDate / ParseBoolean(this string @this) | Read text as another type in invariant culture. Invalid text errors the pipeline rather than throwing. | |
Lower / Upper(this string @this) | Change case, invariant. Null stays null. | |
HourOfDay(this DateTime @this) | The hour as an integer pipeline value. | |
ToZone(this DateTime @this, string zoneId) | Converts a UTC value to a time zone. An unknown zone errors the pipeline. | |
Match<Type><Test>, Reject<Type><Test>, Break<Type><Test>, Require<Type><Test>, Ensure<Type><Test> | Roughly 950 typed test steps over double, int, string, DateTime and bool, each in a pipeline form and a plain-value form, for example MatchGreater, RequireInRange, MatchContainsAnyInList, MatchIsWithinBusinessHours. Listed in full, with what each tests, in the Rule Pipeline Reference. |
Reference, Identifier and Utility Extensions
These extensions were added so that rules and the service layer’s agent tools share one exact implementation of the everyday calculations an analyst would otherwise do by hand. Every one is pure: no file, network, process or native access, which a unit test enforces over the compiled code. The time-relative methods that read the server clock (Age, AgeInDays, IsToday, IsFuture, IsPast, IsValidCardExpiry) now have AsOf counterparts that take the reference date as an argument. Time zones are IANA ids such as Europe/London, resolved from the host’s time zone data. Reference tables (ISO 4217 currencies and ISO 3166-1 countries) are embedded in the product and change only with a release.
| Method Signature | Description |
|---|---|
| Numbers and money | |
RoundToNearest(this double @this, double increment) | Rounds to the nearest multiple of an increment, halves away from zero; NaN for a non-positive increment. |
ProductWith(this double @this, params double[]? others) | Multiplies the value by every other value. |
NthRoot(this double @this, double degree) | The real n-th root; NaN for an even root of a negative number. |
Modulo(this double @this, double divisor) | Remainder that takes the sign of the divisor (Euclidean-style), so -7.Modulo(3) is 2. |
AddPercent(this double @this, double percent) | The value increased by a percentage. |
SubtractPercent(this double @this, double percent) | The value decreased by a percentage. |
BaseBeforePercentAdded(this double @this, double percent) | Recovers the amount before a percentage was added, such as net from gross. |
ConvertAtRate(this double @this, double rate) | Multiplies by a supplied positive exchange rate; NaN otherwise. |
ToMinorUnits(this double @this, int exponent) | Exact whole minor units for a currency exponent (0 to 6), halves away from zero. |
FromMinorUnits(this double @this, int exponent) | Exact major units from minor units for a currency exponent. |
RoundToCurrency(this double @this, string? currencyCode) | Rounds to the ISO 4217 precision of a currency code with decimal arithmetic; NaN for an unknown code. |
CurrencyMinorUnitExponent(this string? @this) | ISO 4217 decimal places of a currency code (USD 2, JPY 0, KWD 3), or -1 when unknown. |
IsValidCurrencyCode(this string? @this) | Whether the text is an active ISO 4217 currency code. |
ConvertUnits(this double @this, string? fromUnit, string? toUnit) | Converts between units of one kind: length, mass, area, volume, speed, time, data size and temperature; NaN across kinds. |
ToRomanNumerals(this int @this) | The value from 1 to 3999 as Roman numerals, otherwise empty. |
FromRomanNumerals(this string? @this) | Canonical Roman numerals as a number, otherwise 0. |
ToRadixString(this long @this, int radix) | The value written in a base from 2 to 36. |
FromRadixString(this string? @this, int radix) | Reads digits written in a base from 2 to 36; throws on an invalid digit or overflow. |
| Countries | |
IsValidCountryCode(this string? @this) | Whether the text is an ISO 3166-1 alpha-2 country code. |
CountryAlpha2(this string? @this) | The alpha-2 code for an alpha-2 or alpha-3 code, otherwise empty. |
CountryAlpha3(this string? @this) | The alpha-3 code for an alpha-2 or alpha-3 code, otherwise empty. |
CountryName(this string? @this) | The English short name for an alpha-2 or alpha-3 code, otherwise empty. |
| Dates and time zones | |
AgeAsOf(this DateTime @this, DateTime asOf) | Completed years from the date to an as-of date; the deterministic form of Age. |
AgeInDaysAsOf(this DateTime @this, DateTime asOf) | Whole days from the date to an as-of date; the deterministic form of AgeInDays. |
IsSameDayAs(this DateTime @this, DateTime other) | Whether two date-times share a calendar date. |
IsBefore(this DateTime @this, DateTime other) | Whether the date-time is earlier than another. |
IsAfter(this DateTime @this, DateTime other) | Whether the date-time is later than another. |
DaysBetween(this DateTime @this, DateTime other) | Fractional days from this date-time to another; negative when the other is earlier. |
HoursBetween(this DateTime @this, DateTime other) | Fractional hours from this date-time to another. |
MinutesBetween(this DateTime @this, DateTime other) | Fractional minutes from this date-time to another. |
SecondsBetween(this DateTime @this, DateTime other) | Fractional seconds from this date-time to another. |
WholeMonthsBetween(this DateTime @this, DateTime other) | Completed calendar months to another date, clamping month ends as AddMonths does. |
WholeYearsBetween(this DateTime @this, DateTime other) | Completed years to another date. |
AddBusinessDays(this DateTime @this, int businessDays) | Moves by Monday-to-Friday days, skipping weekends; negative moves backward. |
StartOfQuarter(this DateTime @this) | Midnight on the first day of the calendar quarter. |
EndOfQuarter(this DateTime @this) | The last tick of the calendar quarter. |
FiscalYear(this DateTime @this, int fiscalYearStartMonth) | The fiscal year, named for the calendar year it ends in, for a fiscal year starting in a given month. |
FiscalQuarter(this DateTime @this, int fiscalYearStartMonth) | The fiscal quarter, 1 to 4, for a fiscal year starting in a given month. |
IsLastDayOfMonth(this DateTime @this) | Whether the date is the last day of its month, allowing for leap years. |
IntervalOverlaps(this DateTime start, DateTime end, DateTime otherStart, DateTime otherEnd) | Whether the half-open interval from this start to an end overlaps another interval. |
ToEpochSeconds(this DateTime @this) | Seconds since 1970-01-01T00:00:00Z, treating the value as UTC. |
ToEpochMilliseconds(this DateTime @this) | Milliseconds since 1970-01-01T00:00:00Z, treating the value as UTC. |
FromEpochSeconds(this double @this) | The UTC date-time for a number of epoch seconds. |
FromEpochMilliseconds(this double @this) | The UTC date-time for a number of epoch milliseconds. |
ToIso8601String(this DateTime @this) | Round-trip ISO 8601 text, with a Z suffix for UTC values. |
ToDateTimeWithFormat(this string? @this, string? format) | Parses text with an exact invariant-culture pattern as UTC, or Nothing when it does not match. |
UtcToZone(this DateTime @this, string? zoneId) | The wall-clock time in an IANA time zone for a UTC value; throws for an unknown zone. |
ZoneToUtc(this DateTime @this, string? zoneId) | The UTC value for a wall-clock time in an IANA time zone; throws for an unknown zone or a skipped local time. |
UtcOffsetHoursIn(this DateTime @this, string? zoneId) | The UTC offset in hours of an IANA time zone at a UTC instant; NaN for an unknown zone. |
IsDaylightSavingTimeIn(this DateTime @this, string? zoneId) | Whether daylight saving is in force in an IANA time zone at a UTC instant. |
IsValidTimeZoneId(this string? @this) | Whether the text is a time zone id known to the host. |
| Payment and securities identifiers | |
IbanCountryCode(this string? @this) | Country code of a valid IBAN, otherwise empty. |
IbanCheckDigits(this string? @this) | Check digits of a valid IBAN, otherwise empty. |
IbanBasicBankAccountNumber(this string? @this) | The BBAN (everything after the first four characters) of a valid IBAN, otherwise empty. |
IbanPrintFormat(this string? @this) | A valid IBAN in upper case in groups of four, otherwise empty. |
BicInstitutionCode(this string? @this) | The four-letter institution code of a valid BIC, otherwise empty. |
BicCountryCode(this string? @this) | The country code of a valid BIC, otherwise empty. |
BicLocationCode(this string? @this) | The location code of a valid BIC, otherwise empty. |
BicBranchCode(this string? @this) | The branch code of a valid BIC, XXX for an eight-character BIC, otherwise empty. |
LuhnCheckDigit(this string? @this) | The Luhn check digit that completes a digit string, or -1 for non-digits. |
CardIssuerPrefix(this string? @this, int length) | The first n digits (1 to 11) of a card number, ignoring spaces and hyphens, otherwise empty. |
IsValidIsin(this string? @this) | Whether the text is a 12-character ISIN with a valid check digit. |
IsValidLei(this string? @this) | Whether the text is a 20-character LEI passing ISO 17442 mod-97. |
IsValidCusip(this string? @this) | Whether the text is a nine-character CUSIP with a valid check digit. |
IsValidSedol(this string? @this) | Whether the text is a seven-character SEDOL with a valid check digit. |
IsValidAbaRoutingNumber(this string? @this) | Whether the text is a nine-digit ABA routing number passing its weighted checksum. |
IsValidCardExpiryAsOf(this string? @this, DateTime asOf) | Whether an MM/YY or MM/YYYY expiry is still valid at an as-of date; the deterministic form of IsValidCardExpiry. |
IsValidUuid(this string? @this) | Whether the text parses as a UUID. |
UuidVersion(this string? @this) | The version number of a UUID, or -1 when it is not one. |
| Contact details and network addresses | |
IsValidE164PhoneNumber(this string? @this) | Whether the text is an E.164 phone number: +, a non-zero digit, up to 15 digits. |
PhoneNumberDigits(this string? @this) | Digits only, keeping a leading + and turning a 00 prefix into +. |
IsValidDomainName(this string? @this) | Whether the text is a syntactically valid domain name of at least two labels. |
TopLevelDomain(this string? @this) | The last label of a host name or of the domain of an email address, in lower case. |
UrlHost(this string? @this) | The lower-case host of an absolute URL, punycode for international names; empty for file and share URLs. |
UrlScheme(this string? @this) | The lower-case scheme of an absolute URL; empty for file and share URLs. |
QueryStringValue(this string? @this, string? key) | The decoded value of a named parameter in a URL or query string, otherwise empty. |
IsIPv4Address(this string? @this) | Whether the text is a dotted-quad IPv4 address. |
IsIPv6Address(this string? @this) | Whether the text is an IPv6 address, including IPv4-mapped forms. |
NormaliseIpAddress(this string? @this) | The canonical text of an IP address, mapping IPv4-mapped IPv6 to IPv4, otherwise empty. |
IsPrivateIpAddress(this string? @this) | Whether the address is private: RFC 1918, carrier-grade NAT 100.64.0.0/10 or IPv6 unique local. |
IsLoopbackIpAddress(this string? @this) | Whether the address is a loopback address. |
IsReservedIpAddress(this string? @this) | Whether the address is reserved: unspecified, loopback, link-local, multicast, documentation or benchmarking ranges. |
IsPublicIpAddress(this string? @this) | Whether the address is neither private nor reserved. |
IsInCidr(this string? @this, string? cidr) | Whether the address falls inside a CIDR range of the same family. |
CidrFirstAddress(this string? @this) | The network address of a CIDR range, otherwise empty. |
CidrLastAddress(this string? @this) | The last address of a CIDR range, otherwise empty. |
CidrAddressCount(this string? @this) | The number of addresses in a CIDR range, otherwise NaN. |
IPv4AddressToNumber(this string? @this) | An IPv4 address as an unsigned 32-bit number, otherwise -1. |
NumberToIPv4Address(this long @this) | A number from 0 to 4294967295 as an IPv4 address, otherwise empty. |
| Geography | |
InitialBearingDegrees(this double latitude1, double longitude1, double latitude2, double longitude2) | Initial compass bearing from the first point to the second, in degrees; NaN for out-of-range coordinates. |
IsValidCoordinate(this double latitude, double longitude) | Whether the latitude and longitude are in range. |
ToGeohash(this double latitude, double longitude, int precision) | A geohash of 1 to 12 characters for the latitude and longitude, otherwise empty. |
GeohashLatitude(this string? @this) | The latitude of the centre of a geohash cell, otherwise NaN. |
GeohashLongitude(this string? @this) | The longitude of the centre of a geohash cell, otherwise NaN. |
| Text | |
WordCount(this string? @this) | Number of whitespace-separated words. |
LineCount(this string? @this) | Number of lines, counting CR, LF and CRLF breaks; 0 for empty text. |
CountOccurrences(this string? @this, string? value) | Non-overlapping case-sensitive occurrences of a substring. |
DistinctCharacterCount(this string? @this) | Number of different characters. |
LongestCharacterRun(this string? @this) | Length of the longest run of one repeated character. |
CollapseWhitespace(this string? @this) | Trimmed, with each run of whitespace replaced by one space. |
ToSlug(this string? @this) | Lower-case ASCII letters and digits joined by hyphens. |
TokenAt(this string? @this, string? separator, int index) | The token at a zero-based position after splitting on a separator; negative positions count from the end. |
TokenCount(this string? @this, string? separator) | Number of tokens after splitting on a separator. |
RemoveControlCharacters(this string? @this) | The text without control characters other than tab, CR and LF. |
UnicodeNormalised(this string? @this, string? form) | The text in Unicode normalisation form NFC, NFD, NFKC or NFKD. |
RegexReplace(this string? @this, string pattern, string? replacement) | Replaces every match of a pattern, with a 250 ms match time limit. |
RegexCapture(this string? @this, string pattern, int group) | A numbered group of the first match of a pattern, otherwise empty, with a 250 ms match time limit. |
RegexMatchCount(this string? @this, string pattern) | Number of matches of a pattern, with a 250 ms match time limit. |
EscapedForRegex(this string? @this) | The text escaped to match itself literally inside a pattern. |
| Name matching | |
DamerauDistance(this string? @this, string? other) | Edit distance counting an adjacent transposition as one edit. |
DiceSimilarity(this string? @this, string? other) | Dice bigram similarity from 0 to 1 on case-, accent- and punctuation-folded text. |
TokenSortSimilarity(this string? @this, string? other) | Jaro-Winkler similarity after sorting words, so word order does not matter. |
TokenSetSimilarity(this string? @this, string? other) | Share of words that best-match between the two texts, from 0 to 1. |
SoundsLike(this string? @this, string? other) | Whether two names sound alike word by word under Soundex. |
NormalisedForMatching(this string? @this) | The name folded for matching: lower case, no accents or punctuation, no leading titles or trailing company suffixes. |
| Encoding and hashing | |
EncodeBase64Url(this string? @this) | URL-safe Base64 of the UTF-8 bytes, without padding. |
DecodeBase64Url(this string? @this) | Decodes URL-safe Base64 to UTF-8 text. |
ToHexUtf8(this string? @this) | Lower-case hex of the UTF-8 bytes. |
FromHexUtf8(this string? @this) | Decodes hex, with an optional 0x prefix, to UTF-8 text. |
Sha256Hex(this string? @this) | Lower-case hex SHA-256 digest of the UTF-8 bytes. |
Sha384Hex(this string? @this) | Lower-case hex SHA-384 digest of the UTF-8 bytes. |
Sha512Hex(this string? @this) | Lower-case hex SHA-512 digest of the UTF-8 bytes. |
Sha1Hex(this string? @this) | Lower-case hex SHA-1 digest, for matching legacy values only. |
Md5Hex(this string? @this) | Lower-case hex MD5 digest, for matching legacy values only. |
HmacSha256Hex(this string? @this, string? key) | Lower-case hex HMAC-SHA-256 under a key. |
HmacSha512Hex(this string? @this, string? key) | Lower-case hex HMAC-SHA-512 under a key. |
Crc32Hex(this string? @this) | CRC-32 (IEEE) checksum as eight hex digits. |
| JSON and XML | |
IsValidJson(this string? @this) | Whether the text is well-formed JSON of at most 1,000,000 characters and 64 levels. |
JsonTextAt(this string? @this, string? path) | The value at a path such as $.a.b[0] as text: strings unquoted, anything else as JSON; empty when missing. |
JsonNumberAt(this string? @this, string? path) | The number at a path, otherwise NaN. |
JsonArrayLengthAt(this string? @this, string? path) | The length of the array at a path, otherwise -1. |
JsonHasPath(this string? @this, string? path) | Whether a path exists and is not null. |
JsonMinified(this string? @this) | The JSON without insignificant whitespace, otherwise empty. |
IsValidXml(this string? @this) | Whether the text is well-formed XML without a DTD. |
XmlTextAt(this string? @this, string? xpath) | Text of the first node selected by an XPath expression, otherwise empty; DTDs and entities are refused. |
Methods that could reach the file system or run arbitrary delegates (SaveAs, PathCombine, IfTrue, IfFalse and the TextWriter overloads of HtmlEncode, HtmlDecode and HtmlAttributeEncode) have been removed from this library, so they are no longer rule tokens. A regular expression that takes longer than 250 ms on a value throws RegexMatchTimeoutException instead of holding the rule thread.
Pipeline, Calculation and Fuzzy List Extensions
Three groups of extensions are documented in full elsewhere, and are listed in the table above so that the tokens are discoverable from here.
- Pipeline extensions turn a rule into a chain of guards that stops at the first decision, for example
Matched = Payload.Amount.RequireInRange(123.45, 543.21).MatchGreater(400). There is noStart()to write. A pipeline converts toTrueonly when it has decided matched, so a rule with no deciding step fails closed. The grammar, the outcomes and every step are in the Rule Pipeline Reference, and the reasoning is in Rule Authoring Methodology. - Calculation extensions are the
Doublemethods above that return a number, for exampleTTLCounter.DeclinedSpend.RatioOf(TTLCounter.TotalSpend). An undefined result isNaN, never zero or infinity, andNaNfails every comparison. Each hasAbove,Below,InRangeandOutsideRangecomparison steps. See Calculations on continuous values for the recipes. - Fuzzy list extensions match a value against a List token loosely, for example
Payload.Name.IsSomehowInList(List.Whatever, "damerau=1,soundex,notitles"). The options string and every algorithm are in the Rule Pipeline Reference.
Two behaviours are worth knowing before reaching for these. A plain method that already exists on the value’s own type, such as string.Trim or double.Round, is bound by VB before an extension of the same name, so Payload.Amount.Round(1) is the static Double.Round and not the extension; begin with Start() in that case. And a pipeline step called on a plain value never throws on a null or NaN input, it fails the test.
Fraud/AML Extension Examples
The extensions below are the most recently added and are the ones most likely to need a worked example rather than a bare signature, because the receiver (@this, the value the rule’s fluent call is written against) is easy to place wrong when there is more than one number of the same type in the parameter list. Every example uses the same convention as the rest of this page: Payload.FieldName reads a field from the transaction being evaluated, and the call is written exactly as it would appear in a rule.
For HaversineDistanceKilometers, HaversineDistanceMiles and ImpliedTravelSpeedKmh, the receiver (@this) is latitude1 and the first explicit argument is longitude1 – i.e. the call is always <latitude1>.MethodName(<longitude1>, <latitude2>, <longitude2>, ...), both points given as (latitude, longitude) pairs in that order:
' Distance in kilometers between the customer's registered address and this transaction's location
If (Payload.HomeLatitude.HaversineDistanceKilometers(Payload.HomeLongitude, Payload.TransactionLatitude, Payload.TransactionLongitude) > 500) Then
Matched = True
End If
' Impossible-travel check: speed implied by two consecutive transaction locations and the hours between them
If (Payload.PreviousLatitude.ImpliedTravelSpeedKmh(Payload.PreviousLongitude, Payload.TransactionLatitude, Payload.TransactionLongitude, Payload.HoursSincePreviousTransaction) > 900) Then
Matched = True
End If
For the remaining new extensions, the receiver is always the single value being tested or transformed, and every other value is an explicit argument in the order shown in the signature:
' Structuring / smurfing: amount sits within 10% below a 10,000 reporting threshold
If (Payload.Amount.IsJustBelowThreshold(10000, 10)) Then
Matched = True
End If
' Suspiciously round amount, e.g. an exact multiple of 1000
If (Payload.Amount.IsRoundAmount(1000)) Then
Matched = True
End If
' How unusual this amount is versus the customer's own historical mean/standard deviation
If (Payload.Amount.ZScore(Payload.CustomerMeanAmount, Payload.CustomerStandardDeviationAmount) > 3) Then
Matched = True
End If
' Percentage jump versus the customer's previous transaction amount
If (Payload.Amount.PercentageChangeFrom(Payload.PreviousAmount) > 300) Then
Matched = True
End If
' Card/IMEI number checksum validation
If (Not Payload.CardNumber.IsValidLuhn()) Then
Matched = True
End If
' IBAN checksum validation on a wire transfer's beneficiary account
If (Not Payload.BeneficiaryIban.IsValidIban()) Then
Matched = True
End If
' Fuzzy match between the payload's stated name and a sanctions-list name already on file
If (Payload.CustomerName.JaroWinklerSimilarity(Payload.WatchlistName) > 0.9) Then
Matched = True
End If
' Phonetic match, catches misspellings a similarity score alone would miss
If (Payload.CustomerName.Soundex() = Payload.WatchlistName.Soundex()) Then
Matched = True
End If
' Randomness of a freshly-supplied account/reference identifier -- high entropy suggests it was generated, not chosen
If (Payload.AccountReference.ShannonEntropy() > 3.5) Then
Matched = True
End If
' Display-safe masking, e.g. for a case note or notification -- never for the value a rule matches on
Payload.MaskedCardNumber = Payload.CardNumber.MaskExceptLast(4)
' Multi-accounting via Gmail-style "+tag" addresses: two payloads normalise to the same real inbox
If (Payload.Email.NormalizeEmailAlias() = Payload.PreviousEmail.NormalizeEmailAlias()) Then
Matched = True
End If
' Synthetic-looking account number, e.g. "...123456..."
If (Payload.AccountNumber.HasSequentialDigits(6)) Then
Matched = True
End If
GreatestCommonDivisor, LeastCommonMultiple, DigitSum, Clamp, Lerp, LevenshteinDistance and SimilarityTo follow the same rule: the receiver is the value on the left of the call, every other value is an argument in signature order, for example Payload.CustomerName.SimilarityTo(Payload.WatchlistName) or Payload.Amount.Clamp(0, 10000).
BusinessDaysUntil, QuarterOfYear and IsoWeekOfYear follow the DateTime extensions above them in this table: Payload.SettlementDate.BusinessDaysUntil(Payload.ValueDate), Payload.TransactionDate.QuarterOfYear(), Payload.TransactionDate.IsoWeekOfYear().
A second batch, added the same way, rounds out coverage of common card, identity and geofencing checks. As above, the receiver is the value being tested and every other value is an explicit argument in signature order:
' Geofence: is this transaction within 50km of the customer's registered address?
If (Not Payload.HomeLatitude.IsWithinRadiusKm(Payload.HomeLongitude, Payload.TransactionLatitude, Payload.TransactionLongitude, 50)) Then
Matched = True
End If
' Invoice amount must match the purchase order within 2%
If (Not Payload.InvoiceAmount.IsWithinPercentOf(Payload.PurchaseOrderAmount, 2)) Then
Matched = True
End If
' Card scheme routing/segmentation from the PAN's IIN/BIN prefix
If (Payload.CardNumber.CardNetwork() = "AmericanExpress") Then
Matched = True
End If
' Reject an already-elapsed or malformed card expiry
If (Not Payload.CardExpiry.IsValidCardExpiry()) Then
Matched = True
End If
' Malformed beneficiary BIC/SWIFT code on a wire transfer
If (Not Payload.BeneficiaryBic.IsValidBic()) Then
Matched = True
End If
' Free-mail domain check, or grouping by domain
If (Payload.Email.EmailDomain() = "example.com") Then
Matched = True
End If
' New account fraud: account opened very recently
If (Payload.AccountOpenedDate.AgeInDays() < 2) Then
Matched = True
End If
' Corporate wire transfer initiated outside normal business hours
If (Not Payload.TransactionDate.IsWithinBusinessHours(9, 17)) Then
Matched = True
End If
DigitCount, LetterCount, InitialsOf and LeadingSignificantDigit are simple building blocks for the same style of rule – for example Payload.TaxId.DigitCount() = 9 to enforce a fixed-length numeric identifier, or Payload.Amount.LeadingSignificantDigit() to build a Benford’s Law check against an expected first-digit frequency table held elsewhere in the rule.