You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Components/Utilities/MaskAlgorithms/BlockMask.cs

117 lines
3.2 KiB

// Copyright (c) MudBlazor 2021
// MudBlazor licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Connected;
public record struct Block(char MaskChar, int Min = 1, int Max = 1);
public class BlockMask : RegexMask
{
public BlockMask(params Block[] blocks) : base(null)
{
if (blocks.Length == 0)
throw new ArgumentException("supply at least one block", nameof(blocks));
Blocks = blocks;
Delimiters = "";
}
public BlockMask(string delimiters, params Block[] blocks) : this(blocks)
{
Delimiters = delimiters ?? "";
}
public Block[] Blocks { get; protected set; }
protected override void InitInternals()
{
base.InitInternals();
Blocks ??= new Block[0];
Mask = BuildRegex(Blocks);
_regex = new Regex(Mask);
}
protected override void InitRegex()
{
// BlockMask inits regex itself (but after base init), no need to do it twice
// so don't call base init here
//base.InitRegex();
}
/// <summary>
/// Build the progressive working regex from the block and delimiter definitions
/// Note: a progressive regex must match partial input!!!!
/// </summary>
/// <param name="blocks"></param>
/// <returns></returns>
protected virtual string BuildRegex(Block[] blocks)
{
var s = new StringBuilder();
int i = 0;
int blockIndex = 0;
s.Append("^");
foreach (var b in blocks)
{
for (int j = 0; j < b.Min; j++)
{
if (i > 0)
s.Append("(");
if (_maskDict.TryGetValue(b.MaskChar, out var maskDef))
s.Append(maskDef.Regex);
else
s.Append(Regex.Escape(b.MaskChar.ToString()));
}
i += b.Min;
if (b.Max > b.Min)
{
for (int j = b.Min; j < b.Max; j++)
{
s.Append("(");
if (_maskDict.TryGetValue(b.MaskChar, out var maskDef))
s.Append(maskDef.Regex);
else
s.Append(Regex.Escape(b.MaskChar.ToString()));
}
for (int j = b.Min; j < b.Max; j++)
s.Append(")?");
}
if (_delimiters.Count > 0 && blockIndex < blocks.Length - 1)
{
s.Append("([");
foreach (var d in _delimiters)
s.Append(Regex.Escape(d.ToString()));
s.Append("]");
i++;
}
blockIndex++;
}
for (int j = 0; j < i - 1; j++)
s.Append(")?");
s.Append("$");
return s.ToString();
}
public override void UpdateFrom(IMask other)
{
base.UpdateFrom(other);
var o = other as BlockMask;
if (o == null)
return;
Blocks = o.Blocks ?? new Block[0];
Delimiters = o.Delimiters;
_initialized = false;
Refresh();
}
}