数字与字符串相互转换

时间:2021-05-04 17:52:34
有这样一个需求,一张表有一个自增的Int类型的主键列,在页面显示的时候想转成4位或5位,由数字,字母,或数字加字母组成的字符串,并且要求可以逆向转换,各位高手有什么好的方案,可以*定义规则,谢谢!

21 个解决方案

#1


 
某个id=123345,加入它代表csdn38
那么id=123456呢?

看过《潜伏》、《黎明之前》吗?数字可以跟字典对应起来,它可以翻译成可见字符。
4-5位也太短了。

动用几百万的数据量的字段翻译id成字符,成本也太高了。

#2


数字与字符串相互转换
吓死我了!lz的头像怎么和孟大哥的一样!!!

#3


如果是出于安全考虑可以用RSA加密,解密

#4


如果不是用于传输保密,那么用一般的DES对称加密方法就可以了

#5


自己拼装流水号

#6



        #region 加密解密
        /// <summary>
        /// DES对称加密方法
        /// </summary>
        /// <param name="InitData">原始待加密数据</param>
        /// <param name="SecretKey">加密密钥,密钥长度必须为八位有效英文字符</param>
        public string EncryptData(object InitData, string SecretKey)
        {
            try
            {
                string _newsecretkey = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(SecretKey + "123456(your key)", "MD5").ToLower();
                string newSecretKey = _newsecretkey.Substring(12, 4) + _newsecretkey.Substring(25, 4);
                DESCryptoServiceProvider des = new DESCryptoServiceProvider();
                //把字符串放到byte数组中    
                Byte[] inputByteArray = Encoding.Default.GetBytes(InitData.ToString());
                //建立加密对象的密钥和偏移量
                des.Key = ASCIIEncoding.ASCII.GetBytes(newSecretKey);
                //原文使用ASCIIEncoding.ASCII方法的GetBytes方法 
                des.IV = ASCIIEncoding.ASCII.GetBytes(newSecretKey);
                //使得输入密码必须输入英文文本
                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
                cs.Write(inputByteArray, 0, inputByteArray.Length);
                cs.FlushFinalBlock();
                StringBuilder ret = new StringBuilder();
                foreach (Byte b in ms.ToArray())
                {
                    ret.AppendFormat("{0:X2}", b);
                }
                ret.ToString();
                return ret.ToString();
            }
            catch
            {
                return "";
            }
        }
        /// <summary>
        /// DES对称解密方法
        /// </summary>
        /// <param name="EncryptedData">待解密数据</param>
        /// <param name="SecretKey">解密密钥,必须是加密时的密钥,密钥长度必须为八位有效英文字符,例如"12secret"</param>
        public string DecryptData(object EncryptedData, string SecretKey)
        {
            try
            {
                string _newsecretkey = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(SecretKey + "123456(your key)", "MD5").ToLower();
                string newSecretKey = _newsecretkey.Substring(12, 4) + _newsecretkey.Substring(25, 4);
                string pToDecrypt = EncryptedData.ToString();
                DESCryptoServiceProvider des = new DESCryptoServiceProvider();
                Byte[] inputByteArray = new byte[pToDecrypt.Length / 2];
                for (int x = 0; x < pToDecrypt.Length / 2; x++)
                {
                    int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
                    inputByteArray[x] = (byte)i;
                }
                //建立加密对象的密钥和偏移量,此值重要,不能修改 
                des.Key = ASCIIEncoding.ASCII.GetBytes(newSecretKey);
                des.IV = ASCIIEncoding.ASCII.GetBytes(newSecretKey);
                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
                cs.Write(inputByteArray, 0, inputByteArray.Length);
                cs.FlushFinalBlock();
                return System.Text.Encoding.Default.GetString(ms.ToArray());
            }
            catch
            {
                return "";
            }
        }

#7


那你要new DataTable了,数据类型要和数据库里的基本一样,不过ID可以设置成string的,遍历从数据库中查出来的,然后拼接,取的时候再阶断
DataTable ndt=new DataTable();
ndt.Column.add("NID",typeof(string));
.....
//遍历数据库取出的表
foreach(DataRow dr in dt)
{
   DataRow ndr=ndt.NewRow();
   ndr["NID"]="2013"+dr["ID"].ToString();
   
}
取数据的时候就 int ID=int.Prase(ndr["NID"].ToString().Substring(4,ndr["NID"].ToString().length-4))

#8


加密,解密不行的,要求是转成4位或5位字符串的,楼上的,可能没有考虑ID的长度,因为ID长度不固定,最短是1位,最长是6位

#9


那自己写函数了。。

#10


我想可能要用进制转换,求算法,函数等

#11


数字与字符串相互转换

#12


看自己想要的规则是什么。
数字,字母,或数字加字母组成的字符串这些到底是如何的。如里面是否规定开始是什么。字母占几位,数字占几位。应该是不重复的。甚至可以直接生成加到数据库里,这样就可*转找了。

#13


开始是什么,字母占几位,数字占几位,这些都没有限制,只要一一对应,不重复就可以了

#14


转成16进制不得了

#15


16进制存不下自己搞36进制(0-Z)进位

#16


楼上说的不错,32进制实现起来可能更容易一些

#17


如果你不想让自己的算法这么容易被猜出来的话,还可以仿造base64编码的原理,一个整数占四字节,6位的数字顶多用到3个字节就是24位,把低24位它按位切成4截,每截是6位,可能的值是0到63,下同base64编码。其实本质上跟实现个64进制差不多

#18



using System;

class Program
{
    static void Main()
    {
        Int32 value = Int32.MaxValue;
        Console.WriteLine(value);
        String valueString = Scale36.To36(value);
        Console.WriteLine(valueString);
        Console.WriteLine(Scale36.ToInt(valueString));
        Console.ReadKey();
    }
}
public class Scale36
{
    private const Int32 NUMDVALUE = 48;
    private const Int32 CHARDVALUE = 55;
    public static String To36(Int32 value)
    {
        if (value <= 0)
        {
            return String.Empty;
        }
        Int32 remainder = value % 36;
        Int32 result = value / 36;
        String result36 = To36Char(remainder).ToString();
        while (result > 36)
        {
            remainder = result % 36;
            result = result / 36;
            result36 = To36Char(remainder).ToString() + result36;
        }
        if (result != 0)
        {
            result36 = To36Char(result).ToString() + result36;
        }
        return result36;
    }
    public static Int32 ToInt(String value)
    {
        if (String.IsNullOrEmpty(value)
            || String.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentNullException("value");
        }
        Int32 result = 0;
        for (int l = value.Length - 1, p = 0; l >= 0; l--, p++)
        {
            Int32 c = ToInt(value[l]);
            result += c * GetSquared(p);
        }
        return result;
    }
    private static Int32 ToInt(Char value)
    {
        Int32 code = (Int32)value;
        if (code >= 48 && code <= 57)
        {
            return code - NUMDVALUE;
        }
        if (code >= 65 && code <= 90)
        {
            return code - CHARDVALUE;
        }
        throw new ArgumentOutOfRangeException("[0-9A-Z]");
    }
    private static Char To36Char(Int32 value)
    {
        if (value < 0 || value > 36)
        {
            throw new ArgumentOutOfRangeException("[0-36]");
        }
        if (value <= 9)
        {
            return ((Char)(value + NUMDVALUE));
        }
        return ((Char)(value + CHARDVALUE));
    }
    private static Int32 GetSquared(Int32 c)
    {
        Int32 result = 1;
        while (c >= 1)
        {
            result = result * 36;
            c--;
        }
        return result;
    }
}



36进制5位存不下,
LZ可考虑下把小写字母也加进去,
36+26=62进制

#19


唔,我想到一种更懒的方法,将后整数的3字节取出来,分别将每个字节强制转换为字符,组成一个3字符的字符串,使用base64编码转换出来是个4字符的字符串

#20


18楼 乱舞春秋 ,你好,谢谢你写的算法,不过有点问题,1296~1332,这之间的数,从字符串到数字转换出错
 Console.WriteLine(Scale36.ToInt(valueString));

#21


引用 20 楼 jbhou 的回复:
18楼 乱舞春秋 ,你好,谢谢你写的算法,不过有点问题,1296~1332,这之间的数,从字符串到数字转换出错
 Console.WriteLine(Scale36.ToInt(valueString));


public class Scale36
{
    public static readonly String MapString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    public static String To36String(Int32 number)
    {
        if (number <= 0)
        {
            return String.Empty;
        }
        Int32 remainder = number % 36;
        Int32 result = number / 36;
        String result36 = To36Char(remainder).ToString();
        while (result >= 36)
        {
            remainder = result % 36;
            result = result / 36;
            result36 = To36Char(remainder).ToString() + result36;
        }
        if (result != 0)
        {
            result36 = To36Char(result).ToString() + result36;
        }
        return result36;
    }
    public static Char To36Char(Int32 number)
    {
        if (number < 0 || number >= MapString.Length)
        {
            throw new IndexOutOfRangeException("[0-36]");
        }
        return MapString[number];
    }

    public static Int32 ToInt32(String value)
    {
        if (String.IsNullOrEmpty(value)
            || String.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentNullException("value");
        }
        Int32 result = 0;
        for (int l = value.Length - 1, p = 0; l >= 0; l--, p++)
        {
            Int32 c = ToInt32(value[l]);
            result += c * GetSquared(p);
        }
        return result;
    }
    public static Int32 ToInt32(Char value)
    {
        Int32 number = MapString.IndexOf(value);
        if (number == -1)
        {
            throw new ArgumentOutOfRangeException("[0-9A-Z]");
        }
        return number;
    }

    private static Int32 GetSquared(Int32 squared)
    {
        Int32 result = 1;
        while (squared >= 1)
        {
            result = result * 36;
            squared--;
        }
        return result;
    }
}

上次这里出问题了
while (result  >= 36)
改进下

#1


 
某个id=123345,加入它代表csdn38
那么id=123456呢?

看过《潜伏》、《黎明之前》吗?数字可以跟字典对应起来,它可以翻译成可见字符。
4-5位也太短了。

动用几百万的数据量的字段翻译id成字符,成本也太高了。

#2


数字与字符串相互转换
吓死我了!lz的头像怎么和孟大哥的一样!!!

#3


如果是出于安全考虑可以用RSA加密,解密

#4


如果不是用于传输保密,那么用一般的DES对称加密方法就可以了

#5


自己拼装流水号

#6



        #region 加密解密
        /// <summary>
        /// DES对称加密方法
        /// </summary>
        /// <param name="InitData">原始待加密数据</param>
        /// <param name="SecretKey">加密密钥,密钥长度必须为八位有效英文字符</param>
        public string EncryptData(object InitData, string SecretKey)
        {
            try
            {
                string _newsecretkey = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(SecretKey + "123456(your key)", "MD5").ToLower();
                string newSecretKey = _newsecretkey.Substring(12, 4) + _newsecretkey.Substring(25, 4);
                DESCryptoServiceProvider des = new DESCryptoServiceProvider();
                //把字符串放到byte数组中    
                Byte[] inputByteArray = Encoding.Default.GetBytes(InitData.ToString());
                //建立加密对象的密钥和偏移量
                des.Key = ASCIIEncoding.ASCII.GetBytes(newSecretKey);
                //原文使用ASCIIEncoding.ASCII方法的GetBytes方法 
                des.IV = ASCIIEncoding.ASCII.GetBytes(newSecretKey);
                //使得输入密码必须输入英文文本
                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
                cs.Write(inputByteArray, 0, inputByteArray.Length);
                cs.FlushFinalBlock();
                StringBuilder ret = new StringBuilder();
                foreach (Byte b in ms.ToArray())
                {
                    ret.AppendFormat("{0:X2}", b);
                }
                ret.ToString();
                return ret.ToString();
            }
            catch
            {
                return "";
            }
        }
        /// <summary>
        /// DES对称解密方法
        /// </summary>
        /// <param name="EncryptedData">待解密数据</param>
        /// <param name="SecretKey">解密密钥,必须是加密时的密钥,密钥长度必须为八位有效英文字符,例如"12secret"</param>
        public string DecryptData(object EncryptedData, string SecretKey)
        {
            try
            {
                string _newsecretkey = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(SecretKey + "123456(your key)", "MD5").ToLower();
                string newSecretKey = _newsecretkey.Substring(12, 4) + _newsecretkey.Substring(25, 4);
                string pToDecrypt = EncryptedData.ToString();
                DESCryptoServiceProvider des = new DESCryptoServiceProvider();
                Byte[] inputByteArray = new byte[pToDecrypt.Length / 2];
                for (int x = 0; x < pToDecrypt.Length / 2; x++)
                {
                    int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
                    inputByteArray[x] = (byte)i;
                }
                //建立加密对象的密钥和偏移量,此值重要,不能修改 
                des.Key = ASCIIEncoding.ASCII.GetBytes(newSecretKey);
                des.IV = ASCIIEncoding.ASCII.GetBytes(newSecretKey);
                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
                cs.Write(inputByteArray, 0, inputByteArray.Length);
                cs.FlushFinalBlock();
                return System.Text.Encoding.Default.GetString(ms.ToArray());
            }
            catch
            {
                return "";
            }
        }

#7


那你要new DataTable了,数据类型要和数据库里的基本一样,不过ID可以设置成string的,遍历从数据库中查出来的,然后拼接,取的时候再阶断
DataTable ndt=new DataTable();
ndt.Column.add("NID",typeof(string));
.....
//遍历数据库取出的表
foreach(DataRow dr in dt)
{
   DataRow ndr=ndt.NewRow();
   ndr["NID"]="2013"+dr["ID"].ToString();
   
}
取数据的时候就 int ID=int.Prase(ndr["NID"].ToString().Substring(4,ndr["NID"].ToString().length-4))

#8


加密,解密不行的,要求是转成4位或5位字符串的,楼上的,可能没有考虑ID的长度,因为ID长度不固定,最短是1位,最长是6位

#9


那自己写函数了。。

#10


我想可能要用进制转换,求算法,函数等

#11


数字与字符串相互转换

#12


看自己想要的规则是什么。
数字,字母,或数字加字母组成的字符串这些到底是如何的。如里面是否规定开始是什么。字母占几位,数字占几位。应该是不重复的。甚至可以直接生成加到数据库里,这样就可*转找了。

#13


开始是什么,字母占几位,数字占几位,这些都没有限制,只要一一对应,不重复就可以了

#14


转成16进制不得了

#15


16进制存不下自己搞36进制(0-Z)进位

#16


楼上说的不错,32进制实现起来可能更容易一些

#17


如果你不想让自己的算法这么容易被猜出来的话,还可以仿造base64编码的原理,一个整数占四字节,6位的数字顶多用到3个字节就是24位,把低24位它按位切成4截,每截是6位,可能的值是0到63,下同base64编码。其实本质上跟实现个64进制差不多

#18



using System;

class Program
{
    static void Main()
    {
        Int32 value = Int32.MaxValue;
        Console.WriteLine(value);
        String valueString = Scale36.To36(value);
        Console.WriteLine(valueString);
        Console.WriteLine(Scale36.ToInt(valueString));
        Console.ReadKey();
    }
}
public class Scale36
{
    private const Int32 NUMDVALUE = 48;
    private const Int32 CHARDVALUE = 55;
    public static String To36(Int32 value)
    {
        if (value <= 0)
        {
            return String.Empty;
        }
        Int32 remainder = value % 36;
        Int32 result = value / 36;
        String result36 = To36Char(remainder).ToString();
        while (result > 36)
        {
            remainder = result % 36;
            result = result / 36;
            result36 = To36Char(remainder).ToString() + result36;
        }
        if (result != 0)
        {
            result36 = To36Char(result).ToString() + result36;
        }
        return result36;
    }
    public static Int32 ToInt(String value)
    {
        if (String.IsNullOrEmpty(value)
            || String.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentNullException("value");
        }
        Int32 result = 0;
        for (int l = value.Length - 1, p = 0; l >= 0; l--, p++)
        {
            Int32 c = ToInt(value[l]);
            result += c * GetSquared(p);
        }
        return result;
    }
    private static Int32 ToInt(Char value)
    {
        Int32 code = (Int32)value;
        if (code >= 48 && code <= 57)
        {
            return code - NUMDVALUE;
        }
        if (code >= 65 && code <= 90)
        {
            return code - CHARDVALUE;
        }
        throw new ArgumentOutOfRangeException("[0-9A-Z]");
    }
    private static Char To36Char(Int32 value)
    {
        if (value < 0 || value > 36)
        {
            throw new ArgumentOutOfRangeException("[0-36]");
        }
        if (value <= 9)
        {
            return ((Char)(value + NUMDVALUE));
        }
        return ((Char)(value + CHARDVALUE));
    }
    private static Int32 GetSquared(Int32 c)
    {
        Int32 result = 1;
        while (c >= 1)
        {
            result = result * 36;
            c--;
        }
        return result;
    }
}



36进制5位存不下,
LZ可考虑下把小写字母也加进去,
36+26=62进制

#19


唔,我想到一种更懒的方法,将后整数的3字节取出来,分别将每个字节强制转换为字符,组成一个3字符的字符串,使用base64编码转换出来是个4字符的字符串

#20


18楼 乱舞春秋 ,你好,谢谢你写的算法,不过有点问题,1296~1332,这之间的数,从字符串到数字转换出错
 Console.WriteLine(Scale36.ToInt(valueString));

#21


引用 20 楼 jbhou 的回复:
18楼 乱舞春秋 ,你好,谢谢你写的算法,不过有点问题,1296~1332,这之间的数,从字符串到数字转换出错
 Console.WriteLine(Scale36.ToInt(valueString));


public class Scale36
{
    public static readonly String MapString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    public static String To36String(Int32 number)
    {
        if (number <= 0)
        {
            return String.Empty;
        }
        Int32 remainder = number % 36;
        Int32 result = number / 36;
        String result36 = To36Char(remainder).ToString();
        while (result >= 36)
        {
            remainder = result % 36;
            result = result / 36;
            result36 = To36Char(remainder).ToString() + result36;
        }
        if (result != 0)
        {
            result36 = To36Char(result).ToString() + result36;
        }
        return result36;
    }
    public static Char To36Char(Int32 number)
    {
        if (number < 0 || number >= MapString.Length)
        {
            throw new IndexOutOfRangeException("[0-36]");
        }
        return MapString[number];
    }

    public static Int32 ToInt32(String value)
    {
        if (String.IsNullOrEmpty(value)
            || String.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentNullException("value");
        }
        Int32 result = 0;
        for (int l = value.Length - 1, p = 0; l >= 0; l--, p++)
        {
            Int32 c = ToInt32(value[l]);
            result += c * GetSquared(p);
        }
        return result;
    }
    public static Int32 ToInt32(Char value)
    {
        Int32 number = MapString.IndexOf(value);
        if (number == -1)
        {
            throw new ArgumentOutOfRangeException("[0-9A-Z]");
        }
        return number;
    }

    private static Int32 GetSquared(Int32 squared)
    {
        Int32 result = 1;
        while (squared >= 1)
        {
            result = result * 36;
            squared--;
        }
        return result;
    }
}

上次这里出问题了
while (result  >= 36)
改进下