大写汉字转阿拉伯数字c语言,阿拉伯数字转中文数字方法详解(C++实现)
阿拉伯?dāng)?shù)字與中文數(shù)字沒(méi)有一一對(duì)應(yīng)關(guān)系,不存在直接轉(zhuǎn)換的公式化算法,因此需要根據(jù)兩種數(shù)字體系的特點(diǎn)精心構(gòu)造轉(zhuǎn)換算法。
中文計(jì)數(shù)有一個(gè)特點(diǎn),就是“零”的使用變化多端。阿拉伯?dāng)?shù)字中數(shù)字的權(quán)位依靠數(shù)字在整個(gè)數(shù)字長(zhǎng)度中的偏移位置確定,因此數(shù)字中間出現(xiàn)的0用于標(biāo)記數(shù)字的偏移位置,即便是連續(xù)出現(xiàn)的0也不能省略。中文計(jì)數(shù)方式中每個(gè)數(shù)字的權(quán)位都直接跟在數(shù)字后面,因此代表連續(xù)出現(xiàn)的若干個(gè)0。
盡管如此,也不是所有的情況都使用“零”,比如阿拉伯?dāng)?shù)字 20001234,中文數(shù)字表示為“二千萬(wàn)一千二百三十四”,沒(méi)有用一個(gè)“零”;再比如阿拉伯?dāng)?shù)字 12000,中文數(shù)字表示為“一萬(wàn)二千”,也沒(méi)有用“零”;但是對(duì)于阿拉伯?dāng)?shù)字 10210300,中文數(shù)字表示為“一千零二十一萬(wàn)零三百”,兩次出現(xiàn)“零”。
針對(duì)這種情況,中文數(shù)字對(duì)“零”的使用總結(jié)起來(lái)有以下三條規(guī)則:
以 10000 為小節(jié),小節(jié)的結(jié)尾即使是 0,也不使用“零”。
小節(jié)內(nèi)兩個(gè)非?0 數(shù)字之間要使用“零”。
當(dāng)小節(jié)的“千”位是 0 時(shí),若本小節(jié)的前一小節(jié)無(wú)其他數(shù)字,則不用“零”,否則就要用“零”。
從阿拉伯?dāng)?shù)字到中文數(shù)字的轉(zhuǎn)換,第一步是以“萬(wàn)”為單位分節(jié),并確定節(jié)權(quán)位。第二步是對(duì)每小節(jié)內(nèi)的數(shù)字確定權(quán)位,并按照前面的三種方法處理“零”的問(wèn)題:
一個(gè)轉(zhuǎn)換示例
以阿拉伯?dāng)?shù)字 200001010200 為例,首先以“萬(wàn)”為單位對(duì)其分節(jié),可分為三節(jié):2000 0101 0200:
第一節(jié) 2000,節(jié)權(quán)位是“億”,因?yàn)檫@一節(jié)的 0 都在結(jié)尾,根據(jù)規(guī)則 1,此處不使用“零”,直接表示為“二千億”。
第二節(jié) 0101,節(jié)權(quán)位是“萬(wàn)”,因兩個(gè) 1 之間有 0,根據(jù)規(guī)則?2,101 可以描述為“一百零一”。另外,此節(jié)的千位是 0,根據(jù)規(guī)則 3,因本小節(jié)前還有數(shù)字,因此需要用“零”。也就是說(shuō),本小節(jié)需要兩個(gè)“零”。
最后一個(gè)小節(jié),結(jié)尾的兩個(gè) 0 根據(jù)規(guī)則 1,不使用“零”,但是千位的 0 根據(jù)規(guī)則 3,需要使用“零”。
根據(jù)以上分析,將三個(gè)小節(jié)的轉(zhuǎn)換結(jié)果組合在一起,阿拉伯?dāng)?shù)字 200001010200 的中文表示就是“二千億零一百零一萬(wàn)零二百”。
從這個(gè)例子可以看出來(lái),對(duì)阿拉伯?dāng)?shù)字分節(jié),確定數(shù)字的權(quán)位很簡(jiǎn)單,最難處理的就是 0 的轉(zhuǎn)換,需要根據(jù)三個(gè)規(guī)則靈活選擇是否需要使用“零”。
轉(zhuǎn)換算法設(shè)計(jì)
設(shè)計(jì)阿拉伯?dāng)?shù)字轉(zhuǎn)中文數(shù)字的算法,也可以遵循上例中的兩個(gè)步驟來(lái)處理,但是需要解決三個(gè)問(wèn)題。
第一個(gè)問(wèn)題是單個(gè)數(shù)字的轉(zhuǎn)換,這個(gè)并不難,因?yàn)榘⒗當(dāng)?shù)字 0?9 與相應(yīng)的中文數(shù)字是一一對(duì)應(yīng)的。對(duì)這個(gè)轉(zhuǎn)換設(shè)計(jì)算法非常簡(jiǎn)單,可以定義中文數(shù)字表:
const char *chnNumChar[CHN_NUM_CHAR_COUNT] = {"零","一","二","三","四","五","六","七","八","九"};
待轉(zhuǎn)換的阿拉伯?dāng)?shù)字作為const char *chnUnitSection[] = {"萬(wàn)","億","萬(wàn)億"};
對(duì)于 32 位正數(shù)能表達(dá)的最大數(shù)來(lái)說(shuō),最大節(jié)權(quán)是“萬(wàn)億”己經(jīng)足夠了,如果要轉(zhuǎn)換更大的數(shù),可以延伸這個(gè)節(jié)權(quán)表的定義,比如增加“億億”。數(shù)字中最低的節(jié)沒(méi)有節(jié)權(quán),使用空字符const char *chnUnitChar[] = {"十","百","千"};
最低位的權(quán)位是空字符串,處理方式和節(jié)權(quán)位的處理方式一樣。數(shù)字權(quán)位的確定并不困難,通過(guò)移位就可以確定每個(gè)數(shù)字對(duì)應(yīng)的權(quán)位。阿拉伯?dāng)?shù)字的權(quán)位是隱含在數(shù)字的位數(shù)中的,使用 0 作為占位符。比如數(shù)字 1000,要使1處在千位,一定會(huì)補(bǔ) 3 個(gè) 0 作為占位符,否則1就不代表“一千”。
既然每一位的權(quán)都在固定的位置上,只要記錄移位的次數(shù)就可以確定阿拉伯?dāng)?shù)字的權(quán)位,以移位次數(shù)做下標(biāo),直接查 chnUnitSection 和 chnUnitChar 表就可以得到正確的中文數(shù)字的權(quán)位。
第三個(gè)需要解決的問(wèn)題是如何處理中文“零”。這個(gè)問(wèn)題稍微有點(diǎn)困難,需要根據(jù)文章開(kāi)頭給出的三個(gè)規(guī)則靈活判斷,此外,對(duì)于連續(xù)出現(xiàn)的阿拉伯?dāng)?shù)字 0,也只能用一個(gè)中文“零”。
算法實(shí)現(xiàn)
轉(zhuǎn)換算法首先要對(duì)阿拉伯?dāng)?shù)字分節(jié),并確定節(jié)權(quán)位名稱。num 對(duì) 10000 取模可得到一個(gè) section,將這個(gè) section 轉(zhuǎn)成中文數(shù)字,然后根據(jù)節(jié)的位置補(bǔ)上節(jié)權(quán)位,即可完成一個(gè)節(jié)的中文數(shù)字轉(zhuǎn)換。重復(fù)這個(gè)過(guò)程,直到 num 等于 0 為止,整個(gè)轉(zhuǎn)換就算完成。
unitPos 變量記錄節(jié)的位置,0 對(duì)應(yīng)空字符串,1 對(duì)應(yīng)“萬(wàn)”,2 對(duì)應(yīng)“億”,隨著 unitPos 的增加,節(jié)權(quán)位也越來(lái)越大。全 0 的節(jié)不需要節(jié)權(quán)位,這個(gè)在代碼中也有處理。根據(jù)規(guī)則 3 的定義,如果一節(jié)內(nèi)數(shù)字的千位是 0,需要根據(jù)前面是否還有數(shù)字決定是否需要加“零”,NumberToChinese() 函數(shù)中利用變量 needZero 和 while(num > 0) 循環(huán)語(yǔ)句,巧妙地做了這個(gè)加“零”處理,省去了一個(gè)if判斷。
//num == 0需要特殊處理,直接返回"零"
void NumberToChinese(unsigned int num, std::string& chnStr)
{
int unitPos = 0;
std::string strIns;
bool needZero = false;
while(num > 0)
{
unsigned int section = num % 10000;
if(needZero)
{
chnStr.insert(0, chnNumChar[0]);
}
SectionToChinese(section, strIns);
/*是否需要節(jié)權(quán)位? */
strIns += (section != 0) ? chnUnitSection[unitPos] : chnUnitSection[0];
chnStr.insert(0, strIns);
/*千位是0需要在下一個(gè)section補(bǔ)零*/
needZero = (section < 1000) && (section > 0);
num = num / 10000;
unitPos++;
}
}
SectionToChinese() 函數(shù)將一個(gè)節(jié)的數(shù)字轉(zhuǎn)換成中文數(shù)字,利用中文數(shù)字表 chnNumChar 轉(zhuǎn)換中文數(shù)字,利用表 chnUnitChar 得到數(shù)字權(quán)位,unitPos 變量用作權(quán)位索引。SectionToChinese() 函數(shù)的關(guān)鍵部分是對(duì) 0 的處理,根據(jù)規(guī)則 1 和規(guī)則 2,小節(jié)結(jié)尾的 0 不需要轉(zhuǎn)換成“零”,但是兩個(gè)數(shù)字之間的 0 需要轉(zhuǎn)換成“零”。如果兩個(gè)數(shù)字之間有 多個(gè) 0,也只轉(zhuǎn)換一個(gè)“零”,變量 zero 用于控制“零”的轉(zhuǎn)換,避免出現(xiàn)多個(gè)“零”連在一起的情況。
void SectionToChinese(unsigned int section, std::string& chnStr)
{
std::string strIns;
int unitPos = 0;
bool zero = true;
while(section > 0)
{
int v = section % 10;
if(v == 0)
{
if( (section ==0) || Izero )
{
zero = true; /*需要補(bǔ),zero的作用是確保對(duì)連續(xù)的多個(gè),只補(bǔ)一個(gè)中文零*/
chnStr.insert(0, chnNumChar[v]);
}
}
else
{
zero = false; //至少有一個(gè)數(shù)字不是
strIns = chnNumChar[v]; //此位對(duì)應(yīng)的中文數(shù)字
strIns += chnUnitChar [unitPos]; //此位對(duì)應(yīng)的中文權(quán)位
chnStr.insert(0, strIns);
}
unitPos++; //移位
section = section / 10;
}
}
中文大寫(xiě)數(shù)字
中文數(shù)字還有一個(gè)很有意思的現(xiàn)象,就是中文數(shù)字大寫(xiě)。所謂的大寫(xiě)其實(shí)就是用一些筆畫(huà)復(fù)雜的漢字代替簡(jiǎn)單的數(shù)字漢字,其目的就是為了保證其不容易被篡改。中文大寫(xiě)用“壹貳叁肆伍陸柒捌玫”代替“一二三四五六七八九”,用“拾佰仟”代替“十百千”。這些數(shù)字的繁寫(xiě)其實(shí)在唐代就己經(jīng)出現(xiàn),但正式作為記載錢(qián)糧、稅收等項(xiàng)目用的官方數(shù)字,是在明朝初年著名的“郭桓案”之后。
郭桓案:與空印案、胡惟庸案和藍(lán)玉案一起并稱為明初四大案。郭桓案發(fā)生在明朝洪武十八年(1385年),屬于官吏貪污案件。戶部侍郎郭桓等人,串通地方官吏作弊,篡改賬冊(cè),私吞太平、鎮(zhèn)江等府的賦稅,還盜賣官糧。后被揭發(fā),以其涉案金額巨大,對(duì)經(jīng)濟(jì)領(lǐng)域影響深遠(yuǎn)而為世人矚目,對(duì)此,明太祖將六部左、右侍郎以下官員全部處死,地方官吏死于獄中者達(dá)數(shù)萬(wàn)人以上。為了追贓,牽連到全國(guó)各地的小富百姓,遭到抄家破產(chǎn)的不計(jì)其數(shù)。由于牽扯面 廣,全國(guó)百姓對(duì)此案非常不滿意,明太祖為了平息民怨,將審刑官吳席等人也一并處死。
實(shí)現(xiàn)中文大寫(xiě)數(shù)字的轉(zhuǎn)換,只需要將 chnNumChar、chnUnitSection 中的中文數(shù)字和權(quán)位名稱替換成大寫(xiě)數(shù)字就可以了,轉(zhuǎn)換算法是一樣的。如果用于人民幣記賬,可調(diào)整節(jié)權(quán)位的名稱,加上“圓”或“圓整”等權(quán)名,有興趣的讀者可自行完成轉(zhuǎn)換代碼。
總結(jié)
以上是生活随笔為你收集整理的大写汉字转阿拉伯数字c语言,阿拉伯数字转中文数字方法详解(C++实现)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 华为mstp多生成树配置_网络工程师(3
- 下一篇: java mvel_MVEL实现java