87 lines
3.1 KiB
C#
87 lines
3.1 KiB
C#
using System.Text.RegularExpressions;
|
|
|
|
namespace AMREZ.EOP.Application.UseCases.Payments.SlipVerification.QrDecode;
|
|
|
|
public static partial class TransRefParser
|
|
{
|
|
[GeneratedRegex(@"(?i)(?:[?&](?:transref|transactionid|txnid|transid)=)(?<id>[-A-Za-z0-9]{10,64})",
|
|
RegexOptions.Compiled | RegexOptions.IgnoreCase)]
|
|
private static partial Regex QueryId();
|
|
|
|
[GeneratedRegex(@"(?<![A-Za-z0-9])(?<id>[0-9]{6,14}[A-Za-z0-9]{6,40})(?![A-Za-z0-9])",
|
|
RegexOptions.Compiled)]
|
|
private static partial Regex FallbackShape();
|
|
|
|
public static string? TryExtract(string? raw)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(raw)) return null;
|
|
|
|
// 1) ?transRef=... ใน URL
|
|
var q = QueryId().Match(raw);
|
|
if (q.Success) return q.Groups["id"].Value;
|
|
|
|
// 2) เดิน TLV แบบ recursive
|
|
foreach (var val in EnumerateTlvValues(raw))
|
|
{
|
|
// ต้องเป็น a-z0-9 ล้วน ยาวพอสมควร และมีตัวอักษรด้วย (กันเคสเป็นตัวเลขล้วน)
|
|
if (val.Length is >= 18 and <= 40
|
|
&& val.All(IsAlphaNum)
|
|
&& val.Any(char.IsLetter))
|
|
return val;
|
|
}
|
|
|
|
// 3) เผื่อกรณีหลุดรูปแบบ TLV
|
|
var f = FallbackShape().Match(raw);
|
|
return f.Success ? f.Groups["id"].Value : null;
|
|
}
|
|
|
|
private static IEnumerable<string> EnumerateTlvValues(string s)
|
|
{
|
|
int i = 0;
|
|
while (i + 4 <= s.Length)
|
|
{
|
|
// รูปแบบ TLV: [ID(2)][LEN(2)][VALUE(LEN)]
|
|
if (!char.IsDigit(s[i]) || !char.IsDigit(s[i + 1]) ||
|
|
!char.IsDigit(s[i + 2]) || !char.IsDigit(s[i + 3]))
|
|
yield break;
|
|
|
|
var id = s.Substring(i, 2);
|
|
if (!int.TryParse(s.AsSpan(i + 2, 2), out var len)) yield break;
|
|
var end = i + 4 + len;
|
|
if (len < 0 || end > s.Length) yield break;
|
|
|
|
var val = s.Substring(i + 4, len);
|
|
yield return val;
|
|
|
|
// ถ้า value ดูเป็น TLV ซ้อนอยู่ ให้ไล่ต่อ
|
|
if (LooksLikeTlv(val))
|
|
foreach (var inner in EnumerateTlvValues(val))
|
|
yield return inner;
|
|
|
|
// CRC tag "63" ไม่เกี่ยว แต่เราไม่ถึงเงื่อนไข length อยู่แล้ว
|
|
i = end;
|
|
}
|
|
}
|
|
|
|
private static bool LooksLikeTlv(string s)
|
|
{
|
|
int i = 0;
|
|
while (i + 4 <= s.Length)
|
|
{
|
|
if (!char.IsDigit(s[i]) || !char.IsDigit(s[i + 1]) ||
|
|
!char.IsDigit(s[i + 2]) || !char.IsDigit(s[i + 3]))
|
|
return false;
|
|
|
|
if (!int.TryParse(s.AsSpan(i + 2, 2), out var len)) return false;
|
|
i += 4 + len;
|
|
if (i == s.Length) return true;
|
|
if (i > s.Length) return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static bool IsAlphaNum(char c) =>
|
|
(c >= '0' && c <= '9') ||
|
|
(c >= 'A' && c <= 'Z') ||
|
|
(c >= 'a' && c <= 'z');
|
|
} |