帮忙写一个正则表达式要求转换中文字为阿拉伯数字

字符串的格式为:十二斤,五十千克等,是数量+单位形式
替换完为:12斤,50千克等
不用考虑小数,但是要考虑零

C币不多了,求各位大神帮忙

15个回答

楼主,您所提问的问题其实不是难的,观察下中文的数值写法,“十”,“百”,“千”,“万”,“亿”这些修饰符其实是一个基数。主要修饰它前面的数字,
有了前面的数字,只要想要的乘以对应的基数(10,100,1000,10000,100000000)再分别相加就可以得到对应的阿拉伯数字了,当然,中文数字对应的
阿拉伯数字还是要自己判断的。这就是思路,有了思路,只需要编写捕获到中文数值中的数字,问题就迎刃而解啦。但是,有一点说明,对应一些复杂的
中文数字的话,需要二次捕获数值再相加,例如前面的层数提到的 五千六百九十七万三千二百一十二斤,其中 五千六百九十七万。万修饰符前面的数字
也是组合而来。所以得从 五千六百九十七中再捕获一次数字。具体实现如下(c#写法,控制台显示):
正则如下:用于捕获中文数字
([零一二三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟亿]+亿)?零?([一二三四五六七八九十百千壹贰叁肆伍陆柒捌玖拾佰仟]+万)?零?([一二三四五六七八九十百壹贰叁肆伍陆柒捌玖拾佰][千仟])?零?([一二三四五六七八九十壹贰叁肆伍陆柒捌玖拾][百佰])?零?([一二三四五六七八九壹贰叁肆伍陆柒捌玖]?[十拾])?零?([一二三四五六七八九壹贰叁肆伍陆柒捌玖])?

代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace regexp_help
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("请输入要转换的中文数量:");
string strPreviousText = Console.ReadLine();
string strRegExp = @"([零一二三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟亿]+亿)?零?([一二三四五六七八九十百千壹贰叁肆伍陆柒捌玖拾佰仟]+万)?零?([一二三四五六七八九十百壹贰叁肆伍陆柒捌玖拾佰][千仟])?零?([一二三四五六七八九十壹贰叁肆伍陆柒捌玖拾][百佰])?零?([一二三四五六七八九壹贰叁肆伍陆柒捌玖]?[十拾])?零?([一二三四五六七八九壹贰叁肆伍陆柒捌玖])?";
string strAllValue = "";
string strSpecifier = "";
int dFormatValue = 0;
MatchCollection matchs = Regex.Matches(strPreviousText, strRegExp); //匹配中文数量
strAllValue = matchs[0].ToString();
strSpecifier = strPreviousText.Remove(0, matchs[0].ToString().Length);
foreach (Match match in matchs)
{
int i = 0;
GroupCollection groups = match.Groups;
foreach (Group group in groups)
{
if (i != 0) {//首个捕获组不获取,因为它是整个数字文本
if (group.ToString() != "")
{
dFormatValue += formatTextToNumber(group.ToString());
}
}
i++;
}
}

        Console.WriteLine("转换后的文本:{0}", dFormatValue + strSpecifier);
        Console.ReadKey();
    }

    public static int formatTextToNumber(string strVal) {
        int dReturn = 0;
        if (strVal.Length == 1)
        {
            dReturn = getNumber(strVal);
        }
        else {
            string strNumber = strVal.Substring(0, strVal.Length - 1);
            string strSpecifier = strVal.Substring(strVal.Length - 1, 1);
            if (strVal.Length == 2)
            {
                dReturn = getNumber(strNumber) * getBaseNumber(strSpecifier);
            }

            //复杂数字要递归取阿拉伯数字,如五百二十万,五百二十相对于“万”修饰符是组合数字
            if (strVal.Length > 2) {
                string strRegExp = @"([零一二三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟亿]+亿)?零?([一二三四五六七八九十百千壹贰叁肆伍陆柒捌玖拾佰仟]+万)?零?([一二三四五六七八九十百壹贰叁肆伍陆柒捌玖拾佰][千仟])?零?([一二三四五六七八九十壹贰叁肆伍陆柒捌玖拾][百佰])?零?([一二三四五六七八九壹贰叁肆伍陆柒捌玖]?[十拾])?零?([一二三四五六七八九壹贰叁肆伍陆柒捌玖])?";
                MatchCollection matchs = Regex.Matches(strNumber, strRegExp);  //匹配中文数量
                foreach (Match match in matchs)
                {
                    int i = 0;
                    GroupCollection groups = match.Groups;
                    foreach (Group group in groups)
                    {
                        if (i != 0)
                        {//首个捕获组不获取,因为它是整个数字文本
                            if (group.ToString() != "")
                            {
                                dReturn += formatTextToNumber(group.ToString());
                            }
                        }
                        i++;
                    }
                }
                dReturn *= getBaseNumber(strSpecifier);
            }
        }

        return dReturn;
    }

    //获取单数字文本对应阿拉伯数字
    public static int getNumber(string strVal) {
        int dFormatValue = 0;
        switch (strVal)
        {
            case "一":
            case "壹":
                dFormatValue = 1;
                break;
            case "二":
            case "贰":
                dFormatValue = 2;
                break;
            case "三":
            case "叁":
                dFormatValue = 3;
                break;
            case "四":
            case "肆":
                dFormatValue = 4;
                break;
            case "五":
            case "伍":
                dFormatValue = 5;
                break;
            case "六":
            case "陆":
                dFormatValue = 6;
                break;
            case "七":
            case "柒":
                dFormatValue = 7;
                break;
            case "八":
            case "捌":
                dFormatValue = 8;
                break;
            case "九":
            case "玖":
                dFormatValue = 9;
                break;
            case "十":
            case "拾":
                dFormatValue = 10;
                break;
            default:
                dFormatValue = 0;
                break;
        }
        return dFormatValue;
    }

    //获取修饰符对用基数
    public static int getBaseNumber(string strVal) {
        int dFormatValue = 10;
        switch (strVal)
        {
            case "十":
            case "拾":
                dFormatValue = 10;
                break;
            case "百":
            case "佰":
                dFormatValue = 100;
                break;
            case "千":
            case "仟":
                dFormatValue = 1000;
                break;
            case "万":
                dFormatValue = 10000;
                break;
            case "亿":
                dFormatValue = 100000000;
                break;
            default:
                dFormatValue = 10;
                break;
        }
        return dFormatValue;
    }
}

}

测试截图:
测试图例1:
图片说明
测试图例2:
图片说明
测试图例3:
图片说明

tracerll
TRACER_BX 回复miansi7149: 这个问题的关键并不在于如何把中文数字转换为阿拉伯数字啊,是在于匹配中文数字的正则表达式,您认为我喜欢伸手,那无所谓,到这里来提问的都可以看做来伸手的,但事实是只有这个答案的作者给出了匹配中文数字的正则表达式,我本人对正则确实也是不太懂
接近 3 年之前 回复
miansi7149
DEMO_INIT 回复Yirujet: 题主是真的喜欢伸手,解题思路就围绕switch case.哎
接近 3 年之前 回复
qq_27323623
Yirujet 回复TRACER_BX: 。。。。。
接近 3 年之前 回复
tracerll
TRACER_BX 您这个简直太靠谱,允许我膜拜一下
接近 3 年之前 回复

正则有可以筛选特定中文的吗?不太清楚 不过你这种的话 对字符串循环一下 用个switch进行下替换就行了

String newStr = "";
switch(str){
case: “零”: newStr +=0;

......
default: newStr += str; //单位点等不处理
}

qq_35728177
Tsui丶 回复qq_28510795: 十要做判断才能换的
接近 3 年之前 回复
qq_28510795
qq_28510795 我没试,不过我想知道你这个十是打算换成几
接近 3 年之前 回复
tracerll
TRACER_BX 回复Tsui丶: 是啊,恕我愚钝,您写出来看看
接近 3 年之前 回复
qq_35728177
Tsui丶 回复TRACER_BX: 我试了下上面写的正则,发现正则是可以来筛选出来,但是问题又来了,如何对应替换?结果还是要一一对应才行 不然就算拿出来“五千四百”还是要去进一步做处理 感觉还是switch好用些 看起来多 实际写起来也就那么些 0-9 百千万亿
接近 3 年之前 回复
tracerll
TRACER_BX 五千六百九十七万三千二百一十二斤,您受累写个循环字符串替换的方式来看看
接近 3 年之前 回复

正则表达式实现起来有点难吧,你看看这个方法

public double DecodeMoneyCn(string AText)
{
AText = AText.Replace("亿亿", "兆");
AText = AText.Replace("万万", "亿");
AText = AText.Replace("点", "元");
AText = AText.Replace("块", "元");
AText = AText.Replace("毛", "角");
double vResult = 0;
double vNumber = 0; // 当前数字
double vTemp = 0;
int vDecimal = 0; // 是否出现小数点
foreach (char vChar in AText)
{
int i = "零一二三四五六七八九".IndexOf(vChar);
if (i < 0) i = "洞幺两三四五六拐八勾".IndexOf(vChar);
if (i < 0) i = "零壹贰叁肆伍陆柒捌玖".IndexOf(vChar);
if (i > 0)
{
vNumber = i;
if (vDecimal > 0)
{
vResult += vNumber * Math.Pow(10, -vDecimal);
vDecimal++;
vNumber = 0;
}
}
else
{
i = "元十百千万亿".IndexOf(vChar);
if (i < 0) i = "整拾佰仟万亿兆".IndexOf(vChar);
if (i == 5) i = 8;
if (i == 6) i = 12;
if (i > 0)
{
if (i >= 4)
{
vTemp += vNumber;
if (vTemp == 0) vTemp = 1;
vResult += vTemp * Math.Pow(10, i);
vTemp = 0;
}
else vTemp += vNumber * Math.Pow(10, i);
}
else
{
i = "元角分".IndexOf(vChar);
if (i > 0)
{
vTemp += vNumber;
vResult += vTemp * Math.Pow(10, -i);
vTemp = 0;
}
else if (i == 0)
{
vTemp += vNumber;
vResult += vTemp;
vDecimal = 1;
vTemp = 0;
}
}
vNumber = 0;
}
}
return vResult + vTemp + vNumber;
}

private void button1_Click(object sender, EventArgs e)
{
string[] vTestText = {
"十二点五六",
"一亿零一万零五",
"四万万",
"九十八亿七千六百五十四万三千二百一十",
"五元一角四分", "壹佰元整",
"三千五百万",
"九块二毛"};
foreach (string vText in vTestText)
{
Console.WriteLine("DecodeMoneyCn(\"{0}\")={1}", vText,
DecodeMoneyCn(vText));
}

//输出
//DecodeMoneyCn("十二点五六")=2.56
//DecodeMoneyCn("一亿零一万零五")=100010005
//DecodeMoneyCn("四万万")=400000000
//DecodeMoneyCn("九十八亿七千六百五十四万三千二百一十")=9876543210
//DecodeMoneyCn("五元一角四分")=5.14
//DecodeMoneyCn("壹佰元整")=100
//DecodeMoneyCn("三千五百万")=35000000
//DecodeMoneyCn("九块二毛")=9.2
//DecodeMoneyCn("一兆")=1000000000000

}

tracerll
TRACER_BX 网上的方法我都看遍了,请仔细阅读题目,这个字符串并不只含有中文数字,还有单位
接近 3 年之前 回复

(?=.*(.*)|.*(.*))^[a-zA-Z0-9\u4e00-\u9fa5()()]*$|^[a-zA-Z0-9\u4e00-\u9fa5]*$
匹配规则:
1. 完全匹配输入中文,英文,数字以及英文半角括号和中文全角括号;
2. 匹配如有括号必须成对;

(?=.*(.*)|.*(.*))^[a-zA-Z0-9\u4e00-\u9fa5()()]*$|^[a-zA-Z0-9\u4e00-\u9fa5]*$
匹配规则:
1. 完全匹配输入中文,英文,数字以及英文半角括号和中文全角括号;
2. 匹配如有括号必须成对;

小兄弟,問問題態度要端正,別話語中帶著譏諷.最近剛好在做正則表達式的分析,你這個用正則分析不出來的.中文不支持特定字符,一到十等等,也可能是我不知道.我可以給你提供個思路,很簡單就能解決你的問題:
1字符串切割,"五十斤,六十克,三十千克" 單位是有限的,C語言有字符切割,函數strtok;
2 得到若干個字符串"五十斤""六十克""三十千克" 然後 中文零到九對應0-9 十對應10;
3這樣最多有十個switch case 語句;

這樣做也不難.

tracerll
TRACER_BX 回复miansi7149: 当然反观我这个问题的回答,除了C#的博友,只有您和这位Tsui丶 朋友起码是认真回答了,我在此表示衷心的感谢
接近 3 年之前 回复
tracerll
TRACER_BX 回复miansi7149: 其实这个问题的关键并不在于把中文数字转为阿拉伯数字,只是转换数字真的是不难,所以我才会发提问求一个正则,目的就是为了分离中文数字
接近 3 年之前 回复
miansi7149
DEMO_INIT 回复TRACER_BX: 我也不是前辈,我只是同行,热心回答你的问题,反而惹来一身骚,这种题目的主要思想就switch,case有c#的博友已经给你写出来了,思路就是这个思路,问题真的不是那么难.别人好心帮忙换来的态度也不应该是这样,这里大多多同行,给你回答都是出自热心别管对否,不是出于你说的那种装大神,我还跳大神恩.以后请摆正态度.不要凉了热心博友的心.
接近 3 年之前 回复
tracerll
TRACER_BX 回复miansi7149: 气大了伤肝,我原您身体健康
接近 3 年之前 回复
tracerll
TRACER_BX 回复miansi7149: 您干嘛如此激动呢,这不应该是一个前辈的样,请您心平气和,如果我哪句说错了,我给您道歉,至于您写不写出来这个事儿,已经不重要了
接近 3 年之前 回复
miansi7149
DEMO_INIT 回复TRACER_BX: 我tm越想越生氣,我要是寫出來了你管我叫爸爸啊!裝逼.
接近 3 年之前 回复
miansi7149
DEMO_INIT 回复TRACER_BX:哎我打這麼多字就是為了裝逼行了吧,一副惡心的模樣.你另謀高就吧我在這不懂裝懂.我入行半年.給你回答問題真是恥辱.
接近 3 年之前 回复
tracerll
TRACER_BX 试问假如您遇到一个问题,别人告诉你哎呀你这个简单的很啊如此如此,你又明明知道是胡扯,您怎么办
接近 3 年之前 回复
tracerll
TRACER_BX 不是我话中带刺,我就问您一句,五千六百九十七万三千二百一十二斤,这个您用您的方法写出来,我大写的一个服;我说句实话,您这个解题思路是入行半年不到的水平;我看了一圈csdn的这个技术问答,里面有营养的答案太少,不是网上复制粘贴,就是不懂装懂,只能说csdn的技术问答出发点很好,但是基本就完了
接近 3 年之前 回复
 String str = "十二万零四百一十公斤";
        String newStr = "";
        for (int i = 0; i < str.length(); i++) {
            char st = str.charAt(i);
            switch (st) {
            case '零':
                newStr += '0';
                break;
            case '一':
                newStr += '1';
                break;
            case '二':
                newStr += '2';
                break;
            case '三':
                newStr += '3';
                break;
            case '四':
                newStr += '4';
                break;
            case '十':
                if (i + 1 != str.length()) {
                    newStr += '1';
                }
                break;
            case '百':
                break;
            case '千':
                break;
            case '万':
                break;
            default:
                newStr += st;
                break;
            }
        }
        System.out.println(newStr);
    }
qq_35728177
Tsui丶 回复Tsui丶: 当然这个方法是没有考虑过什么性能相关的
接近 3 年之前 回复
qq_35728177
Tsui丶 改写的差不多就这些了其他的什么亿啊就自己去写就是了 这个测试是没问题的 其他情况没测过 具体就自己琢磨下吧
接近 3 年之前 回复

String newStr = "";
switch(str){
case: “零”: newStr +=0;

......
default: newStr += str; //单位点等不处理
}

qq_41295568
qq_41295568 对头
接近 3 年之前 回复

正则有可以筛选特定中文的吗?不太清楚 不过你这种的话 对字符串循环一下 用个switch进行下替换就行了

String newStr = "";
switch(str){
case: “零”: newStr +=0;

......
default: newStr += str; //单位点等不处理
}

String newStr = "";
switch(str){
case: “零”: newStr +=0;

......
default: newStr += str; //单位点等不处理
}

共15条数据 1 尾页
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐