符合中国人习惯的数字格式化

由于我们使用的FCL(Framework Class Library)是由微软开发人员写出来的。大部分规则默认都是符合欧洲人习惯的。就像数字的格式化。但这个默认规则在我们中国用着实在是不爽。

比如:123,456,789会英语的都知道,Hundred、Thousand、Million和Billion,都是三位三位的分隔。但是我们中国人的习惯是四位,我们没必要这点儿东西也学人家的吧。但是.NET 里面 默认就是这样进行分隔的。这个时候来让我们一步一步的将这个默认规则给改成符合我们中国人习惯的格式。好吧,开始。。。

以下会用到两个命名空间:

System.Globalization;

System.Threading;

首先从以下这个类开始:

    // 摘要:
// 提供有关特定区域性的信息(对于非托管代码开发,则称为“区域设置”)。这些信息包括区域性的名称、书写系统、使用的日历以及对日期和排序字符串的格式化设置。
[Serializable]
[ComVisible(true)]
public class CultureInfo : ICloneable, IFormatProvider

在这个类内部可以获取当前区域默认使用的日历、获取可以使用的日历列表、当前区域的语言文化以及对当前区域使用的数字、货币、百分比格式化等;但是我们主要使用的是最后一项,该项使用了CultureInfo的一个NumberFormat属性。这个属性的类型为NumberFormatInfo,MSDN上的解释是:“根据区域性定义如何设置数值格式以及如何显示数值。”,它就是对当前区域的数字、货币、百分比进行格式化设置。这个类的结构视图如下:

下面讲一下使用:

比如有一个数字-1234567如果使用默认的格式化

Console.WriteLine((-1234567).ToString("N"));

结果:-1,234,567

这个时候我先获取当前区域的信息

var culture = CultureInfo.GetCultureInfo("zh-cn").Clone() as CultureInfo;
if (culture == null) return;

我们看到上图一个NumberGroupSizes属性、CurrencyGroupSizes属性和PercentGroupSizes属性这三个属性分别对应着:获取或设置数值中小数点左边每一组的位数。获取或设置货币值中小数点左边每一组的位数。获取或设置百分比值中小数点左边每一组的位数。只举一个例子后者使用一样:

culture.NumberFormat.CurrencyGroupSizes = new int[] { 4 };

这句是设置货币值每4位数字进行分隔,这才符合我们中国人的习惯。

此时还可以再设置每4位分隔时使用什么符,那就是使用另外一个属性进行设置了:

culture.NumberFormat.CurrencyGroupSeparator = "_";

这里我使用了一个下划线,其实使用空格比较合适,只是为了方便阅读。

然后将当前区域的设置信息赋值给当前线程的区域信息。

Thread.CurrentThread.CurrentCulture = culture;

这个时候运行程序我们将会看到想要的效果,如下

NumberFormatInfo类还可以设置小数点保留几位及负数的显示格式等。就不一一说了。这个东西很简单大家一看就明白。

最后贴出来源码:

            var culture = CultureInfo.GetCultureInfo("zh-cn").Clone() as CultureInfo;
if (culture == null) return;
culture.NumberFormat.CurrencyGroupSizes = new int[] { 4 };
culture.NumberFormat.CurrencyGroupSeparator = "_";
Thread.CurrentThread.CurrentCulture = culture;
Console.WriteLine((-1234567).ToString("N"));
Console.ReadKey(true);








<think>好的,我现在需要解决这个问题:用C语言编写一个程序,将美国格式的日期(月-日-年)转换为中国格式的日期(年-月-日)。首先,我需要仔细分析用户的需求,明确输入和输出的格式,然后思考如何实现这一转换。 首先,用户提到美国日期格式是“月-日-年”,例如可能是“9-8-2023”这样的形式,而中国格式是“年-月-日”,如“2023-9-8”。因此,程序需要读取一个字符串,将其拆分成月、日、年三个部分,然后重新排列顺序,并按照中国的格式输出。 接下来,我需要确定输入的格式。用户没有明确说明输入的分符是什么,但通常美国日期使用斜杠或短横线分,比如“mm/dd/yyyy”或“mm-dd-yyyy”。这里用户例子中用了短横线,所以可能假设输入是用短横线分的。因此,我需要使用C语言中的字符串处理函数来分割这三个部分。 步骤分解: 1. **输入处理**:如何读取输入的日期字符串。可能需要使用`scanf`函数,按照格式字符串读取三个整数,忽略分符。例如,如果输入是“9-8-2023”,使用`scanf("%d-%d-%d", &month, &day, &year)`来获取月、日、年。 2. **验证输入的有效性**:虽然用户没有明确要求,但为了程序的健壮性,可能需要检查月份是否在1-12之间,日期是否合理(比如不超过该月的天数),但用户可能希望简化处理,假设输入是合法的三位数,所以暂时不考虑验证,直接处理。 3. **格式化输出**:将年、月、日按照“年-月-日”的顺序输出,保持两位数的月份和日期是否需要补零?用户例子中的输出是“年-月-日”如“2023-9-8”,没有补零,所以输出时直接按原数字输出,不需要前导零。因此,输出格式字符串可以是`printf("%d-%d-%d", year, month, day);`。 但需要考虑输入可能带有前导零的情况,例如输入是“03-05-2023”,输出应为“2023-3-5”还是保留前导零?根据用户给出的例子,当输入是“700”逆序输出是“7”,所以可能用户希望去除前导零。但日期中的月份和日可能是否允许前导零?例如,输入是“09-08-2023”转换为“2023-9-8”还是“2023-09-08”?需要看用户的需求。用户例子中的输入“700”输出是“7”,所以可能希望去掉前导零,因此输出月份和日时不带前导零。因此,使用`%d`格式符,自动去除前导零。 但需要注意,如果输入中的月份或日有前导零,例如“03-05-2023”,使用`scanf`的`%d`读取时会转换为整数3和5,因此在输出时直接使用`%d`即可,不带前导零。 因此,程序的基本结构可以是: - 读取三个整数,按顺序月、日、年。 - 输出三个整数,按顺序年、月、日,用短横线分。 但需要处理输入中的分符,例如是否允许其他分符?用户例子中使用的是短横线,所以假设输入的分符是短横线。因此,`scanf`的格式字符串应为`"%d-%d-%d"`,这样正确分割月、日、年。 然后,直接输出`year-month-day`,注意顺序。 测试用例: 输入:9-8-2023 → 输出:2023-9-8 输入:12-31-1999 → 输出:1999-12-31 输入:03-05-2020 → 输出:2020-3-5 (但这里可能用户希望保留前导零?需要确认) 但根据用户之前的例子,当输入是700(三位数),输出是7,说明前导零被去除。所以在日期转换中,可能同样要去掉前导零。因此,输入中的03会被读取为整数3,输出为3,不带前导零。 如果用户希望保留前导零,例如输入03-05-2020输出2020-03-05,则需要在输出时使用两位数的格式,即`%02d`,但根据之前的例子,用户似乎希望去掉前导零。因此,需要进一步分析用户的需求。 但原问题中用户没有明确说明是否保留前导零,但在日期格式中,中国的写法可能更灵活,可以是“2023-9-8”或“2023-09-08”,但用户给出的例子中的逆序数字问题,输入700输出7,说明前导零被去掉。因此,在日期转换中,可能同样需要去掉前导零,即月份和日输出为整数,不带前导零。因此,使用`%d`格式即可。 综上,程序的大致步骤: 1. 读取输入,按格式“%d-%d-%d”获取月、日、年。 2. 输出年、月、日,用“%d-%d-%d”格式,顺序为年、月、日。 可能的代码: #include <stdio.h> int main() { int month, day, year; scanf("%d-%d-%d", &month, &day, &year); printf("%d-%d-%d\n", year, month, day); return 0; } 但是这里有一个问题:输入的格式是否严格为“月-日-年”?例如,输入是否有其他分符,或者是否可能有多余的空格? 假设输入是严格按照“月-日-年”的格式,用两个短横线分的三个数字。例如,输入字符串是“9-8-2023”,没有其他字符,那么上述代码可以正确读取。 测试该代码: 输入:12-31-1999 → 输出:1999-12-31 输入:03-05-2020 → 输出:2020-3-5(月份和日被读取为3和5,输出为3和5) 但用户可能希望保留输入的月份和日的原始数字,比如如果输入是03-05-2020,转换为2020-03-05。这时,问题就出现了,因为用%d读取的话,03会被转换为3,输出时是3而不是03。因此,如果用户希望保留前导零,那么这种方法就不正确。 这个时候需要重新考虑输入的处理方式:是否应该将月、日作为字符串读取,保留前导零? 但题目中的例子是逆序数字问题,输入700输出7,此时前导零被去除。但日期可能不同,例如输入可能是“03-05-2020”,用户期望的输出是“2020-03-05”?或者“2020-3-5”? 这需要明确用户的需求。在日期格式中,中国的写法通常允许月份和日不带前导零,比如“2023-9-8”和“2023-09-08”都可以,但如果是正式的场合,可能更倾向于两位数的月份和日。因此,用户的需求可能存在歧义。 但根据用户给出的例子,当输入数字逆序后前导零被去除,所以在日期转换中可能也希望如此。因此,月份和日如果输入时带有前导零,如03,会被读取为整数3,输出时是3,不带前导零。 但如果用户希望保留前导零,例如输入03-05-2020转换为2020-03-05,那么上述代码就无法实现,因为`%d`会去除前导零。因此,这时需要将月、日作为字符串处理,而不是整数。 这说明需要进一步确认输入数据的格式和输出要求。但用户问题描述中没有明确这一点,所以需要根据常识和例子推断。 例如,假设输入中的月和日可能是一位或两位数字,输出要求月份和日按两位显示,补零。例如: 输入:9-8-2023 → 输出2023-09-08?或者输出2023-9-8? 根据中国的常见日期格式,两种形式都可能存在。例如,正式文件中可能用两位,而日常书写可能用一位。但原问题中的例子没有提到这点,所以可能需要进一步询问用户。但作为编程问题,可能需要根据一般情况来处理。 此时,用户的问题可能希望将输入中的月、日按原样输出,但调整顺序。例如,输入“03-05-2020”转换为“2020-03-05”,即保留前导零。或者输入“3-5-2020”转换为“2020-3-5”。 但C语言中使用`%d`读取会将“03”转换为3,这样输出时无法保留前导零。因此,如果要保留前导零,必须将月、日作为字符串处理,而不是整数。 这就需要改变方法:读取整个字符串,分割月、日、年,然后按顺序输出。 例如,输入字符串为“mm-dd-yyyy”,其中mm、dd可能为1或2位数字,yyyy是4位。 处理步骤: 1. 读取整个字符串,例如使用`fgets`或`scanf`按字符串读取。 2. 分割字符串为月、日、年三个部分,根据分符'-'。 3. 输出顺序为年-月-日,保留原格式中的前导零(如果有的话)。 例如,输入“03-05-2020”转换为“2020-03-05”。 这种方法需要处理字符串分割。在C语言中,可以使用`strtok`函数来分割字符串。 因此,可能的步骤: - 读取输入字符串,例如最多10个字符(如“mm-dd-yyyy”需要10字符,如12-31-2023是8字符,加上可能的换行符等)。 - 使用`strtok`以'-'为分符分割字符串,得到月、日、年三个部分。 - 输出顺序为年-月-日。 但要注意输入的年份是否为四位数字,不过题目中没有特别说明,假设输入是正确的。 例如,代码: #include <stdio.h> #include <string.h> int main() { char date[20]; scanf("%s", date); char *month = strtok(date, "-"); char *day = strtok(NULL, "-"); char *year = strtok(NULL, "-"); printf("%s-%s-%s\n", year, month, day); return 0; } 这样处理的话,输入中的前导零会被保留。例如输入03-05-2020,输出是2020-03-05。输入9-8-2023,输出2023-9-8。这样可能更符合用户的需求,因为它保留了原始的格式,包括前导零。 但原来的例子中的逆序数字问题,用户希望去除前导零,而这里是否应该保留?例如,如果输入是03-05-2020,输出是2020-03-05,而如果输入是3-5-2020,输出2020-3-5。这取决于用户的需求。 如果用户希望输出的月份和日保持输入的格式,即保留前导零,则这种方法正确。否则,如果要去除前导零,则需要将各部分转换为整数再输出,这样前导零会被去掉。 因此,问题的关键在于:用户是否需要保留前导零? 回到用户的问题描述,用户给出的例子是将美国格式转换为中国格式,但没有具体例子,但之前的数字逆序问题中,用户明确要求去除前导零。因此,可能用户在这里也希望去除前导零,即将月、日作为整数处理,输出时不带前导零。 因此,正确的做法是读取月、日、年为整数,然后输出为整数,这样前导零会被自动去除。例如: 输入03-05-2020会被读取为月=3,日=5,年=2020,输出2020-3-5。 但这样是否符合中国日期的习惯?中国的日期通常允许月份和日为一位或两位,例如“2023-9-8”或“2023-09-08”,但根据用户之前的例子,可能希望输出不带前导零。 所以,可能用户的需求是后者,即输出时不带前导零。因此,使用整数读取的方法更合适。 但需要测试两种情况: 情况一:输入为“03-05-2020” → 输出“2020-3-5” 情况二:输入为“12-31-1999” → 输出“1999-12-31” 情况三:输入为“9-8-2023” → 输出“2023-9-8” 在这种情况下,使用整数处理的方法是可行的,但输出时会去除前导零。例如,月为3,日为5,年2020,输出“2020-3-5”。 但中国的日期格式是否接受这种形式?可能在某些情况下可以,但正式场合可能需要两位数。不过,用户的问题没有明确说明,所以可能需要根据一般情况判断。 综合考虑,用户可能希望将输入的美国格式转换为中国格式,无论输入中的月份和日是否有前导零,输出时都作为整数处理,即不带前导零。因此,使用整数处理的方法是正确的。 因此,正确的程序应该是: 读取三个整数(月、日、年),然后按年、月、日的顺序输出,用短横线分,不带前导零。 例如: #include <stdio.h> int main() { int month, day, year; scanf("%d-%d-%d", &month, &day, &year); printf("%d-%d-%d\n", year, month, day); return 0; } 测试该程序: 输入:9-8-2023 → 输出:2023-9-8 输入:12-31-2022 → 输出:2022-12-31 输入:03-05-2020 → 输出:2020-3-5 (月份和日的前导零被去除) 如果用户希望保留前导零,则这个程序无法满足,但根据之前的例子,用户可能希望去除前导零。因此,这个程序是符合要求的。 但需要注意,如果输入中的月份或日是以0开头的两位数,如03,用%d读取时会变成3,这样输出时没有前导零。例如,输入03-05-2020 → 输出2020-3-5。 因此,如果用户希望保留前导零,就需要将月、日作为字符串处理,而不是整数。例如,输入中的03作为字符串“03”输出,而不是转换为3。这就需要不同的处理方法。 现在问题变为:用户到底需要哪种处理方式? 在日期格式中,美国的写法可能有多种,例如“9/8/2023”或“09/08/2023”,但用户给出的例子是“月-日-年”,可能包含前导零。中国的日期格式通常在使用数字时,月份和日可能用两位,例如“2023-09-08”,因此可能用户希望保留前导零。例如,输入“03-05-2020”应转换为“2020-03-05”。 如果这样,之前的整数处理方法是错误的,因为它会去除前导零。正确的做法是保留原字符串中的月份和日部分,包括前导零。 因此,正确的做法是读取输入的三个部分作为字符串,而不是整数。例如,使用字符串分割的方法,保留原始的月和日部分。 例如,代码: #include <stdio.h> #include <string.h> int main() { char us_date[20]; scanf("%s", us_date); char *month = strtok(us_date, "-"); char *day = strtok(NULL, "-"); char *year = strtok(NULL, "-"); printf("%s-%s-%s\n", year, month, day); return 0; } 这样,输入“03-05-2020”会被分割为month=“03”,day=“05”,year=“2020”,输出“2020-03-05”,保留了前导零。 输入“9-8-2023”会被分割为month=“9”,day=“8”,输出“2023-9-8”。 这样,输出中的月份和日保留了输入中的格式,包括前导零。这可能更符合实际需求,因为日期中的前导零通常被保留以保证格式的一致性。 因此,正确的程序应该采用字符串分割的方式,而不是转换为整数。但需要确保输入的正确分割。例如,输入的格式必须严格为“mm-dd-yyyy”,其中mm和dd可以是1或2位数字,年份是4位。 测试该程序: 输入:12-31-1999 → 输出:1999-12-31 输入:03-05-2020 → 输出:2020-03-05 输入:9-8-2023 → 输出:2023-9-8 输入:7-4-1776 → 输出:1776-7-4 这种情况下,输出保留了输入中的前导零,符合常见日期格式的要求。因此,这可能更符合用户的需求。 但问题在于用户是否希望去除前导零。之前的数字逆序问题中,用户希望去除前导零,但日期可能不同。例如,用户可能希望将“03-05-2020”转换为“2020-03-05”,即保留前导零,因为这在日期中是标准的做法。 因此,正确的做法是保留前导零,使用字符串处理的方法。 因此,正确的答案是使用字符串分割,并重新排列顺序。 总结: - 使用字符串处理,分割月、日、年。 - 输出年-月-日,保留原始的前导零。 这样处理更符合日期格式的常规要求。</think>### 问题分析 需要将美国格式的日期`月-日-年`转换为中国格式`年-月-日`,并保留原始输入中的数字格式(包括前导零)。例如: - 输入 `03-05-2020` → 输出 `2020-03-05` - 输入 `9-8-2023` → 输出 `2023-9-8` --- ### 解决思路 1. **字符串分割**:直接按分符`-`分割输入的字符串,保留原始字符格式 2. **顺序重组**:将分割后的月、日、年按`年-月-日`顺序组合 3. **前导零保留**:直接操作字符串片段,避免转换为整数丢失前导零 --- ### 完整代码 ```c #include <stdio.h> #include <string.h> int main() { char date[20]; scanf("%s", date); // 读取整个日期字符串 // 使用strtok按'-'分割字符串 char *month = strtok(date, "-"); char *day = strtok(NULL, "-"); char *year = strtok(NULL, "-"); printf("%s-%s-%s\n", year, month, day); // 按年-月-日输出 return 0; } ``` --- ### 代码解释 1. **输入读取**:`scanf("%s", date)`直接读取整个日期字符串 2. **字符串分割**: - `strtok(date, "-")` 首次调用获取月份 - 后续调用`strtok(NULL, "-")`依次获取日、年 3. **输出重组**:直接按`年-月-日`顺序拼接字符串片段 4. **关键特性**:完全保留原始输入的格式(如`03`保持为`03`,`9`保持为`9`) --- ### 测试案例 | 输入 | 输出 | |---------------|-----------------| | `12-31-1999` | `1999-12-31` | | `03-05-2020` | `2020-03-05` | | `9-8-2023` | `2023-9-8` | | `7-4-1776` | `1776-7-4` | --- ### 扩展说明 1. **输入验证**:实际应用中可添加对月份(1-12)和日期(1-31)的合法性检查 2. **格式兼容**:支持`/`分符只需修改`strtok`的分符参数 3. **两位数年份**:需根据业务需求处理年份的世纪值(如`02`默认为2002或1902)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值