我有一个c ++程序,它接受一个整数并将其转换为小写和大写字母,类似于excel将列索引转换为列号但也包括小写字母的内容。
#include <string>
#include <iostream>
#include <climits>
using namespace std;
string ConvertNum(unsigned long v)
{
char const digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
size_t const base = sizeof(digits) - 1;
char result[sizeof(unsigned long)*CHAR_BIT + 1];
char* current = result + sizeof(result);
*--current = '\0';
while (v != 0) {
v--;
*--current = digits[v % base];
v /= base;
}
return current;
}
// for testing
int main()
{
cout<< ConvertNum(705);
return 0;
}
我需要vba函数将其反转回原始数字。我没有很多使用C ++的经验,所以我无法弄清楚在vba中反转这个的逻辑。任何人都可以帮忙。
更新1:我不需要编写代码,只需要一些逻辑帮助来反转它。我会尝试将逻辑转换为代码。
更新2:根据答案中提供的精彩解释和帮助,很明显代码没有将数字转换为通常的基数52,这是误导性的。所以我更改了功能名称,以消除未来读者的困惑。
答案 0 :(得分:2)
编辑:通过下面描述的代码转换为十进制的字符串格式不是标准的base-52架构。架构不包括 0 或任何其他数字。因此,不应使用此代码将标准base-52值转换为decimal。
O.K。这是基于在长字符串中根据其位置转换单个字符。字符串是:
chSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
InStr()函数告诉我们 A 位于 1 位置, Z 就位 26 且 a 位于 27 。所有字符都以相同的方式转换。
我使用的不是 Asc(),因为 Asc()在大写和小写字母之间有间隙。
最不重要的字符值乘以52 ^ 0左下一个字符的值乘以52 ^ 1
第三个字符的值乘以由52 ^ 3等代码:
Public Function deccimal(s As String) As Long
Dim chSET As String, arr(1 To 52) As String
Dim L As Long, i As Long, K As Long, CH As String
chSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
deccimal = 0
L = Len(s)
K = 0
For i = L To 1 Step -1
CH = Mid(s, i, 1)
deccimal = deccimal + InStr(1, chSET, CH) * (52 ^ K)
K = K + 1
Next i
End Function
一些例子:
<强> 注:的强>
这不是通常编码碱基的方式。通常基数以 0 开头,并且在任何编码值的位置允许 0 。在我之前的所有 UDF()中,chSET
中的第一个字符是 0 ,我必须使用{{ 1}}
答案 1 :(得分:2)
Gary的学生提供了一种简单易懂的方式来获取我所称的数字&#34; Excel风格基础52&#34;这就是你想要的。
然而,这与通常的基数52略有不同。我将尝试解释常规基数52及其转换的差异。可能有一种更简单的方法,但这是我能想到的最好的方法,也解释了您提供的代码。
作为示例:数字zz..zz表示常规基数52中的51 *(1 + 52 + 52 ^ 2 + ... 52 ^(n-1))和52 *(1 + 52 + 52 ^ Excel样式库52中的2 + ... 52 ^(n-1))因此Excel样式的数字越多,数字越少。 Here是基于位数的差异。这怎么可能?它使用前导零,因此1,01,001等都是不同的数字。为什么我们不这样做呢?它会破坏普通系统的简单算法。
我们不能在基数变化之后将所有数字移位一,我们不能在基数变化之前减去1来反击我们从1开始而不是0的事实.I&#39 ; ll概述了基数10的问题。如果我们使用Excel样式的基数10来对列进行编号,我们必须计算像&#34; 0,1,2,...,9,00,01 ,02,...&#34;。乍一看,看起来我们只需要移动数字,所以我们从1开始计数,但这只能达到第10个数字。
1 2 .. 10 11 .. 20 21 .. 99 100 .. 110 111 //normal counting
0 1 .. 9 00 .. 09 10 .. 88 89 .. 99 000 //excel style counting
你注意到每当我们添加一个新数字时,我们再次转移。为了解决这个问题,我们必须在计算每个数字之前进行1次移位,而不是在计算数字后移位。 (如果我们在52 ^ k,这只会产生影响)请注意,我们仍然将A分配给0,B分配给1等。
通常情况下,你要改变基础的方法是循环使用类似
的东西nextDigit = x mod base //determining the last digit
x = x/base //removing the last digit
//terminate if x = 0
但是现在它是
x = x - 1
nextDigit = x mod base
x = x/base
//terminate if x = 0
所以x先减1!我们快速检查x = 52:
常规基地52:
nextDigit = x mod 52 //52 mod 52 = 0 so the next digit is A
x = x/52 //x is now 1
//next iteration
nextDigit = x mod 52 //1 mod 52 = 1 so the next digit is B
x = x/52 //1/52 = 0 in integer arithmetic
//terminate because x = 0
//result is BA
Excel样式:
x = x-1 //x is now 51
nextDigit = x mod 52 //51 mod 52 = 51 so the next digit is z
x = x/52 //51/52 = 0 in integer arithmetic
//terminate because x=0
//result is z
有效!
现在让我们阅读您的代码:
x % y
表示x mod y
使用整数进行计算时,结果将是一个整数,通过向下舍入来实现。因此39/10将产生3等。
x++
和++x
都将x增加1. 您可以在其他语句中使用它来保存一行代码。 x++
表示在评估语句后x递增,++x
表示在评估语句之前递增
y=f(x++);
与
相同y = f(x);
x = x + 1;
而
y=f(++x);
与
相同x = x + 1;
y = f(x);
这与--
Char* p
创建指向char
。指针指向内存中的某个位置。如果更改指针,则指向其他位置。例如。执行p--
将指针向左移动一个。要读取或写入在该位置保存的值,请使用*p
。例如。 *p="a";
&#34; a&#34;被写入p
指向的内存位置。 *p--="a";
&#34; a&#34;写入内存,但指针向后移动到左边,所以* p现在是&#34; a&#34;左边的内存中的任何内容。
字符串的结尾总是&#39; \ 0&#39;如果计算机读取一个字符串,它会继续,直到找到&#39; \ 0&#39;
希望能够理解代码。这是
#include <string>
#include <iostream>
#include <climits>
using namespace std;
string base52(unsigned long v)
{
char const digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; //The digits. (Arrays start at 0)
size_t const base = sizeof(digits) - 1; //The base, based on the digits that were given
char result[sizeof(unsigned long)*CHAR_BIT + 1]; //The array that holds the answer
//sizeof(unsigned long)*CHAR_BIT is the number of bits of an unsigned long
//which means it is the absolute longest that v can be in any base.
//The +1 is to hold the terminating character '\0'
char* current = result + sizeof(result); //This is a pointer that is supposed to point to the next digit. It points to the first byte after the result array (because its start + length)
//(i.e. it will go through the memory from high to low)
*--current = '\0'; //The pointer gets moved one to the left (to the last char of result and the terminating char is added
//the pointer has to be moved to the left first because it was actually pointing to the first byte after the result.
while (v != 0) { //loop until v is zero (until there are no more digits left.
v--; //v = v - 1. This is the important part that does the 1 -> A part
*--current = digits[v % base]; // the pointer is moved one to the left and the corresponding digit is saved
v /= base; //the last digit is dropped
}
return current; //current is returned, which points at the last saved digit. The rest of the result array (before current) is not used.
}
// for testing
int main()
{
cout<< base52(705);
return 0;
}