Files
2024-04-21 22:47:51 +08:00

203 lines
6.4 KiB
C#
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#region Copyright (C) 2021 (OSS开源系列) 公众号:OSSCore
/***************************************************************************
*   文件功能描述:全局辅助类 - 树形编码生成辅助
*
*   创建人: Kevin
* 创建人Email:1985088337@qq.com
*
*
*****************************************************************************/
#endregion
using OSS.Common.Extension;
namespace OSS.Tools.Num;
/// <summary>
/// 树形编码生成辅助类
/// </summary>
public class TreeNumHelper
{
private const string _paddingNumStr = "0000000000000000000";
private const int _numLength = 19; // long 最大值 19位
private const int _numSmallLength = 16; // 2 ^ 53 -1 16字符长度
/// <summary>
/// 生成小于 2^53 次方的编码
/// js 安全的数值
/// </summary>
/// <param name="parentNum"></param>
/// <param name="maxPreNum"></param>
/// <returns></returns>
public static long JSSafeGenerate(long parentNum, long maxPreNum)
{
return GenerateNum(parentNum, maxPreNum, _numSmallLength);
}
/// <summary>
/// 生成long最大长度的编码(19位长度)
/// </summary>
/// <param name="parentNum"></param>
/// <param name="maxPreNum"></param>
/// <returns></returns>
public static long Generate(long parentNum, long maxPreNum)
{
return GenerateNum(parentNum, maxPreNum, _numLength);
}
/// <summary>
/// 生成编号
/// </summary>
/// <param name="parentNum"></param>
/// <param name="maxPreNum"></param>
/// <param name="numLength">编码长度</param>
/// <returns></returns>
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";
/// <summary>
/// 获取子节点编号区域范围
/// </summary>
/// <param name="parentNum"></param>
/// <returns></returns>
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);
}
/// <summary>
/// 获取直接父级列表,[PLever0,PLever1,PLever2,....]
/// </summary>
/// <param name="treeNum"></param>
/// <returns></returns>
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<long>();
}
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;
}
/// <summary>
/// 补充简化的小树形码
/// </summary>
/// <param name="shortTreeNum"> 小树形码 </param>
/// <returns></returns>
public static long PaddingTreeNum(long shortTreeNum)
{
return PaddingTreeNum(shortTreeNum, _numLength);
}
/// <summary>
/// 补充简化的小树形码(最大值 小于 2^53-1
/// </summary>
/// <param name="smallShortTreeNum"> 小树形码 </param>
/// <returns></returns>
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();
}
}