#region Copyright (C) 2021 (OSS开源系列) 公众号:OSSCore
/***************************************************************************
* 文件功能描述:全局辅助类 - 树形编码生成辅助
*
* 创建人: Kevin
* 创建人Email:1985088337@qq.com
*
*
*****************************************************************************/
#endregion
using OSS.Common.Extension;
namespace OSS.Tools.Num;
///
/// 树形编码生成辅助类
///
public class TreeNumHelper
{
private const string _paddingNumStr = "0000000000000000000";
private const int _numLength = 19; // long 最大值 19位
private const int _numSmallLength = 16; // 2 ^ 53 -1 16字符长度
///
/// 生成小于 2^53 次方的编码
/// js 安全的数值
///
///
///
///
public static long JSSafeGenerate(long parentNum, long maxPreNum)
{
return GenerateNum(parentNum, maxPreNum, _numSmallLength);
}
///
/// 生成long最大长度的编码(19位长度)
///
///
///
///
public static long Generate(long parentNum, long maxPreNum)
{
return GenerateNum(parentNum, maxPreNum, _numLength);
}
///
/// 生成编号
///
///
///
/// 编码长度
///
private static long GenerateNum(long parentNum, long maxPreNum, int numLength)
{
string newNumStr;
if (maxPreNum > 0)
{
var realNumStr = maxPreNum.ToString().TrimEnd('0');
if (parentNum == 0 && realNumStr == "8")
{
// 最高位特殊情况处理
newNumStr = "11"; // 最高位排除 9 (同时不能以0结尾,排除10)
}
else if (realNumStr.EndsWith("9"))
{
// 涉及进位处理
var lastNodeIndex = realNumStr.LastIndexOf('0') + 1;
var lastNodeNum = realNumStr[lastNodeIndex..].ToInt64() + 2;
// 999+2=1001 特殊情况处理
var lastNodeNumStr = (lastNodeNum % 100 == 1)
? lastNodeNum.ToString().Replace('0', '1')
: lastNodeNum.ToString();
newNumStr = string.Concat(realNumStr[..lastNodeIndex], lastNodeNumStr);
}
else
{
newNumStr = (realNumStr.ToInt64() + 1).ToString();
}
}
else if (parentNum > 0)
{
var parentRealNumStr = parentNum.ToString().TrimEnd('0');
if (parentRealNumStr.Length + 2 > numLength)
{
throw new ArgumentOutOfRangeException("编号超出可设置的最大子集");
}
newNumStr = string.Concat(parentRealNumStr, "01");
}
else
{
newNumStr = "1";
}
if (newNumStr.Length > numLength)
throw new ArgumentOutOfRangeException("编号超出可设置的最大子集");
if (newNumStr.Length < numLength)
{
return string.Concat(newNumStr
, _paddingNumStr.Substring(0, numLength - newNumStr.Length))
.ToInt64();
}
return newNumStr.ToInt64();
}
private const string _maxSubPaddingNumStr = "9999999999999999999";
///
/// 获取子节点编号区域范围
///
///
///
public static (long minSubNum, long maxSubNum) FormatSubNumRange(long parentNum)
{
var parentNumStr = parentNum.ToString();
var numLength = parentNumStr.Length;
var realParentNum = parentNumStr.TrimEnd('0');
var paddingLength = numLength - realParentNum.Length ;
if (paddingLength <= 0)
return (parentNum, parentNum);
var minNum = string.Concat(realParentNum, "01", _paddingNumStr.Substring(0, paddingLength-2)).ToInt64();
var maxNum = string.Concat(realParentNum, "0", _maxSubPaddingNumStr.Substring(0, paddingLength-1)).ToInt64();
return (minNum, maxNum);
}
///
/// 获取直接父级列表,[PLever0,PLever1,PLever2,....]
///
///
///
public static long[] FormatParents(long treeNum)
{
var treeNumStr = treeNum.ToString();
var numLength = treeNumStr.Length;
var realParentNum = treeNumStr.TrimEnd('0');
var realParentNumSplits = realParentNum.Split(new[] {'0'}, StringSplitOptions.RemoveEmptyEntries);
if (realParentNumSplits.Length <= 1)
{
return Array.Empty();
}
var tempStr = realParentNumSplits[0];
var parentIds = new long[realParentNumSplits.Length - 1];
for (var i = 0; i < realParentNumSplits.Length - 1; i++)
{
if (i>0)
{
tempStr = string.Concat(tempStr, "0", realParentNumSplits[i]);
}
parentIds[i] = string.Concat(tempStr, _paddingNumStr[..(numLength - tempStr.Length)]).ToInt64();
}
return parentIds;
}
///
/// 补充简化的小树形码
///
/// 小树形码
///
public static long PaddingTreeNum(long shortTreeNum)
{
return PaddingTreeNum(shortTreeNum, _numLength);
}
///
/// 补充简化的小树形码(最大值 小于 2^53-1
///
/// 小树形码
///
public static long PaddingSmallTreeNum(long smallShortTreeNum)
{
return PaddingTreeNum(smallShortTreeNum, _numSmallLength);
}
private static long PaddingTreeNum(long bareTreeNum,int length)
{
var strTreeNum = bareTreeNum.ToString();
if (length<= strTreeNum.Length)
{
return bareTreeNum;
}
return string.Concat(strTreeNum, _paddingNumStr[..(length - strTreeNum.Length)])
.ToInt64();
}
}