c# – Regex series of optional matches with separator depending on state
You could use the following approach:
- Split the input string on the delimiter
-(as @Barmar suggests in their comment to the question post) - Then, for each part of the split input string:
- Use regex to verify that the part starts with an integer
- Verify that the part ends with a valid unit (directly following the integer)
- Verify that the unit ‘size’ is smaller than the preceding unit ‘size’
To check whether the part ends with a valid unit (step 2.2), you can use regex to remove the initial integer part, and then try to find the unit in a dictionary that only contains your valid units. (I am recommending a dictionary rather than a hash set due to step 2.3.)
To check whether the unit ‘size’ is smaller than the preceding unit ‘size’ (step 2.3), the dictionary containing your valid units could have a ‘comparison size’ as the value for the unit (key). E.g. the larger the physical unit, the larger the ‘comparison size’ ("gal": 4, "qt": 3, and so on).
An implementation of this approach could be:
private const char Delimiter="-";
private static readonly Regex StartsWithIntegerRegex = new Regex(@"^(\d+)");
private static readonly Dictionary<string, int> ComparisonSizeByUnit = new()
{
["oz"] = 0,
["cup"] = 1,
["pt"] = 2,
["qt"] = 3,
["gal"] = 4,
};
private static bool IsValidQuantityInput(string quantityInput)
{
if (string.IsNullOrWhiteSpace(quantityInput))
{
return false;
}
var quantities = quantityInput.Split(Delimiter);
if (!TryParseQuantity(quantities[0], out var previousUnitComparisonSize))
{
return false;
}
for (var i = 1; i < quantities.Length; i++)
{
if (!TryParseQuantity(quantities[i], out var unitComparisonSize))
{
return false;
}
if (unitComparisonSize >= previousUnitComparisonSize)
{
return false;
}
previousUnitComparisonSize = unitComparisonSize;
}
return true;
}
private static bool TryParseQuantity(string quantity, out int unitComparisonSize)
{
var quantityStartsWithInteger = StartsWithIntegerRegex.IsMatch(quantity);
if (!quantityStartsWithInteger)
{
unitComparisonSize = 0;
return false;
}
var unit = StartsWithIntegerRegex.Replace(quantity, string.Empty);
return ComparisonSizeByUnit.TryGetValue(unit, out unitComparisonSize);
}
Read more here: Source link
