C#中的字符编码问题

该文件的编码为GB18030,每行的宽度为23个字符,其中第1-8列为员工姓名,第10-23列为工资额。现在我们要写一个C#程序求出该单位员工的平均工资,如下所示:

1using System;

2using System.IO;

3using System.Text;

4

5namespace Skyiv.Ben.Test

6{

7  sealed class Avg

8  {

9    static void Main()

10    {

11      try

12      {

13        Encoding encode = Encoding.GetEncoding("GB18030");

14        using (StreamReader sr = new StreamReader("salary.txt", encode))

15        {

16          decimal avg = 0;

17          long rows = 0;

18          for (; ; rows++)

19          {

20            string s = sr.ReadLine();

21            if (s == null) break;

22            decimal salary = Convert.ToDecimal(s.Substring(9, 14));

23            avg += salary;

24          }

25          avg /= rows;

26          Console.WriteLine(avg.ToString("N2"));

27        }

28      }

29      catch (Exception ex)

30      {

31        Console.WriteLine("错误: " + ex.Message);

32      }

33    }

34  }

35}

36

运行结果如下所示:

错误: 索引和长度必须引用该字符串内的位置

参数名: length

稍一分析(或者使用debug工具),就知道是该程序的第22行出错:

decimal salary = Convert.ToDecimal(s.Substring(9, 14));

实际上,C#中的string的编码是Unicode,每个全角的汉字也只能算一个字符,所以salary.txt中的第一行只有20个字符,第二行是21个字符,第三行是19个字符,均没有达到23个字符,所以s.Substring(9, 14)会抛出异常。实际上,只要把这一行改为以下语句就行了:

decimal salary = Convert.ToDecimal(encode.GetString(encode.GetBytes(s), 9, 14));

重新编译后再运行就可以得到正确的结果了: 329,218,792.83。

其实,更好的办法是把该程序的13-27行替换为以下语句:

        const int bytesPerRow = 23 + 2;

        Encoding encode = Encoding.GetEncoding("GB18030");

        using (BinaryReader br = new BinaryReader(new FileStream("salary.txt", FileMode.Open)))

        {

          if (br.BaseStream.Length % bytesPerRow != 0) throw new Exception("文件长度错");

          decimal avg = 0;

          long rows = br.BaseStream.Length / bytesPerRow;

          for (long i = 0; i < rows; i++)

          {

            byte [] bs = br.ReadBytes(bytesPerRow);

            decimal salary = Convert.ToDecimal(encode.GetString(bs, 9, 14));

            avg += salary;

          }

          avg /= rows;

          Console.WriteLine(avg.ToString("N2"));

        }

现在,假设我们的任务是生成salary.txt,以下程序能工作吗?

1using System;

2using System.IO;

3using System.Text;

4

5namespace Skyiv.Ben.Test

6{

7  sealed class Salary

8  {

9    static void Main()

10    {

11      try

12      {

13        Encoding encode = Encoding.GetEncoding("GB18030");

14        string [] names = {"李富贵", "容闳", "欧阳吹雪"};

15        decimal [] salarys = {0.01m, 2057.38m, 987654321.09m};

16        using (StreamWriter sw = new StreamWriter("salary.txt", false, encode))

17        {

18          for (int i = 0; i < names.Length; i++)

19            sw.WriteLine("{0,-8} {1,14:N2}", names[i], salarys[i]);

20        }

21      }

22      catch (Exception ex)

23      {

24        Console.WriteLine("错误: " + ex.Message);

25      }

26    }

27  }

28}

29

运行结果表明生成的文件中各行的宽度长短不一。怎么办呢?只要把程序中第19行改为:

sw.WriteLine("{0} {1,14:N2}", encode.GetString(encode.GetBytes(names[i].PadRight(8)), 0, 8), salarys[i]);

就行了。

假如salary.txt文件的编码是UTF-16,是否把程序中的

Encoding encode = Encoding.GetEncoding("GB18030");

改为:

Encoding encode = Encoding.Unicode;

就可以了呢?这个问题就留给读者们去思考了。

设想一下,如果在不远的将来能够实现在所有的操作系统中,字符编码都采用UTF-16,并且一个全角字符和一个半角在屏幕显示和在打印机上打印出来时所占的宽度都一样的(等宽字体的情况下,如果不是等宽字体,半角的A和i所占的宽度也不一样)。这时,也就不需要全角和半角概念了(反正大家都一样,全角也就是半角),也就不存在本文中所讨论的问题了,就象现在英语国家的程序员不会有这个问题一样(对他们来说根本就不存在全角字符的概念)。

版权声明:本文为博主http://www.zuiniusn.com原创文章,未经博主允许不得转载。

时间: 2024-10-08 13:59:59

C#中的字符编码问题的相关文章

Android中检测字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法(一)

package com.android.filebrowser; import java.io.*; import java.net.*; public class FileEncodingDetect { static final int GB2312 = 0; static final int ASCII = 1; static final int UTF8 = 2; static final int UNICODE = 3; //static final int GBK = 4; //st

perl脚本中对字符编码的支持

# 使perl程序支持utf8宽字符编码,不添加下面几行打印中文字符时将出现Wide character in print警告或错误.use utf8;binmode(STDIN, ':encoding(utf8)');binmode(STDOUT, ':encoding(utf8)');binmode(STDERR, ':encoding(utf8)');perl脚本处理中文等字符时,有时从文件读出的数据为字节码,需要进行解码才能正确显示.使用Encode模块即可处理.use Encode;#

浅析白盒审计中的字符编码及SQL注入

尽管现在呼吁所有的程序都使用unicode编码,所有的网站都使用utf-8编码,来一个统一的国际规范.但仍然有很多,包括国内及国外(特别是非英语国家)的一些cms,仍然使用着自己国家的一套编码,比如gbk,作为自己默认的编码类型.也有一些cms为了考虑老用户,所以出了gbk和utf-8两个版本. 我们就以gbk字符编码为示范,拉开帷幕.gbk是一种多字符编码,具体定义自行百度.但有一个地方尤其要注意: 通常来说,一个gbk编码汉字,占用2个字节.一个utf-8编码的汉字,占用3个字节.在php中

Python中的字符编码问题

初学Python,本身就在一些语句处有些迷惑,如 a = u'你好',不知加上这个Unicode参数有何作用.一直到做爬虫抓取新闻时,在cmd的输出上总是出现错误.经过检索相关知识后,对一些编码问题做个小总结,其中参杂个人猜测,难免会有错误,以后再慢慢修改了. 1.一定要声明#coding=XXX吗? 首先.py文件中,编码默认是ASCII的,一旦py文件中出现了中文类似编码,IDE就会提示 也就是提示文中出现了非ASCII,建议在文件开始制定编码,当然我们常用的是#coding:utf8 (貌

Android中检测字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法(二)

Intent intent = getIntent(); String contentUri = null; Uri uri =null; if (intent.getData() != null) { uri = intent.getData(); contentUri = "file".equals(uri.getScheme()) ? FileContentProvider.BASE_URI + uri.getEncodedPath() : uri.toString(); Str

ASP中有关字符编码转换的几个有用函数

ASP中有关字符编码转换的几个有用函数 <%1.'UTF转GB---将UTF8编码文字转换为GB编码文字function UTF2GB(UTFStr) for Dig=1 to len(UTFStr)   '如果UTF8编码文字以%开头则进行转换  if mid(UTFStr,Dig,1)="%" then      'UTF8编码文字大于8则转换为汉字    if len(UTFStr) >= Dig+8 then        GBStr=GBStr & Con

转:JAVA中各种字符编码类型转换

import java.io.UnsupportedEncodingException; /** * 转换字符串的编码 */public class ChangeCharset { /** 7位ASCII字符,也叫作ISO646-US.Unicode字符集的基本拉丁块 */ public static final String US_ASCII = "US-ASCII"; /** ISO 拉丁字母表 No.1,也叫作 ISO-LATIN-1 */ public static final

python中的字符编码和转换

1.字符编码初识 最初的字符集是ASCII,ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言,其最多只能用 8 位来表示(一个字节),即:2**8 = 256-1,所以,ASCII码最多只能表示 255 个符号. 随着计算机技术的普及和发展,255个符号显然不满足全世界国家对符号数量的需求,因此各国开始发展自己的一套编码.那么针对中文: 为了

程序中的字符编码

每个程序员都经历过字符乱码的困扰,经过一通折腾后,总算显示正常,但之后似乎还是时不时碰到乱码的问题. 当我们打开notepad或者ultraedit后,这些工具都会自带编码转换的选项,里面各种字符编码格式十分复杂,往往一头雾水. 这里不谈具体编码格式问题,这是一个很学究的话题.其实对于软件开发而言,除非专门做字符编码相关的软件,否则我们一般遇到的最多的也就那么几种字符编码,如utf和gbk.这里要说的是,当我们要考虑字符编码时,理解一个基本的场景模型,然后根据这个模型,在遇到乱码问题后就可以定位