Skip to content

Instantly share code, notes, and snippets.

@GataullinRR
Last active August 25, 2020 11:13
Show Gist options
  • Select an option

  • Save GataullinRR/31d0a26d46d088fc2c9356040f1039a1 to your computer and use it in GitHub Desktop.

Select an option

Save GataullinRR/31d0a26d46d088fc2c9356040f1039a1 to your computer and use it in GitHub Desktop.
using System;
using System.Globalization;
using System.Linq;
using System.Text;
string GenerateIsMoreThanRegexp(double value, bool isInclusive = true, bool isComma = false, int minDecimals = 2, int maxDecimals = 3)
{
if (minDecimals < 1 || maxDecimals < minDecimals) // So the dot must be present
{
throw new NotSupportedException();
}
var operandParts = value.ToString(CultureInfo.InvariantCulture).Split('.');
var wholePart = operandParts[0];
var decimalPart = operandParts.Length == 2
? operandParts[1]
: "0";
if (decimalPart.Length > maxDecimals)
{
throw new ArgumentOutOfRangeException();
}
decimalPart = decimalPart + new string('0',
decimalPart.Length < maxDecimals
? maxDecimals - decimalPart.Length
: 0);
var sb = new StringBuilder();
var separator = isComma ? "," : "\\.";
var wholePartSemanticalLength = wholePart == "0" ? 0 : wholePart.Length;
if (wholePartSemanticalLength != 0) // No duplicate match regexp!
{
// Mored digits => higher
sb.Append($@"|^[1-9]\d{{{wholePartSemanticalLength},}}{separator}\d{{{minDecimals},{maxDecimals}}}$");
}
for (int i = 0; i < wholePart.Length; i++)
{
var elapsedLength = wholePart.Length - i;
var subPart = wholePart[0..i];
var next = int.Parse(wholePart[i..(i + 1)]);
if (next < 9)
{
sb.Append($@"|^{subPart}[{next + 1}-9]\d{{{elapsedLength - 1},}}{separator}\d{{{minDecimals},{maxDecimals}}}$");
}
}
for (int i = 0; i < decimalPart.Length; i++) // Two loops are more understandable than one (I guess so)
{
var subPart = decimalPart[0..i];
var next = int.Parse(decimalPart[i..(i + 1)]);
if (next < 9)
{
var addToMin = i < minDecimals ? minDecimals - i - 1 : 0;
var addToMax = maxDecimals - i - 1; // Already checked
sb.Append($@"|^{wholePart}{separator}{subPart}[{next + 1}-9]\d{{{addToMin},{addToMax}}}$");
}
}
if (isInclusive)
{
var nonZeroDecimals = string.Join("", decimalPart.Reverse().SkipWhile(c => c == '0').Reverse());
var addToMin = nonZeroDecimals.Length <= minDecimals ? minDecimals - nonZeroDecimals.Length : 0;
var addToMax = maxDecimals - nonZeroDecimals.Length; // Already have a check
sb.Append($@"|^{wholePart}{separator}{nonZeroDecimals}\d{{{addToMin},{addToMax}}}$");
}
return sb.ToString()[1..sb.Length];
}
@GataullinRR
Copy link
Author

GataullinRR commented Aug 25, 2020

The code generates regexp that maches any value in format [1-9]\d*.\d{minDecimals, maxDecimals} or 0.\d{minDecimals, maxDecimals} that is higher or equal (isInclusive = true) than "value"

Do not believe it works? Try for yourself!
https://regex101.com/

Example output:

For GenerateIsMoreThanRegexp(0):
^[1-9]\d{0,}\.\d{2,3}$|^0\.[1-9]\d{1,2}$|^0\.0[1-9]\d{0,1}$|^0\.00[1-9]\d{0,0}$|^0\.\d{2,3}$

For GenerateIsMoreThanRegexp(5.2):
^[1-9]\d{1,}\.\d{2,3}$|^[6-9]\d{0,}\.\d{2,3}$|^5\.[3-9]\d{1,2}$|^5\.2[1-9]\d{0,1}$|^5\.20[1-9]\d{0,0}$|^5\.2\d{1,2}$

For GenerateIsMoreThanRegexp(561340.62):
^[1-9]\d{6,}\.\d{2,3}$|^[6-9]\d{5,}\.\d{2,3}$|^5[7-9]\d{4,}\.\d{2,3}$|^56[2-9]\d{3,}\.\d{2,3}$|^561[4-9]\d{2,}\.\d{2,3}$|^5613[5-9]\d{1,}\.\d{2,3}$|^56134[1-9]\d{0,}\.\d{2,3}$|^561340\.[7-9]\d{1,2}$|^561340\.6[3-9]\d{0,1}$|^561340\.62[1-9]\d{0,0}$|^561340\.62\d{0,1}$

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment