字符编码探密--ASCII,UTF8,GBK,Unicode

目录

ASCII 的由来

在计算机的“原始社会”,有人想把日常的使用的语言使用计算机来表示, 我们知道在计算机的世界里面,只有0和1,为了解决尽量多的去表示字符,最终他们决定用8位0和1(一个字节)来表示字符,并且规定当机器读到这几个数据的时候,做出动作或者打印出指定的字符:

遇上0001 0000, 终端就换行;                

遇上0000 0111, 终端就向人们嘟嘟叫;        

遇上‭‭0001 1011‬, 打印机就打印反白的字,或者终端就用彩色显示字母。

这样就形成了最早期的ASCII码表{:target=”_blank”},并把小于32的字符称为“控制字符”,剩下的继续进行编写,一直到127个字符,这样一套完整的字符方案就完成了,终于可以把文字搬到计算机中了。

  当大家都在兴奋的可以在电脑的阅读的文章的时候,新的问题又出现了,随着计算机的普及,很多国家都使用了计算机,原来的ASCII码在使用英语的国家可以无障碍的使用,但到了其它国家就无法满足要求了,所以他们决定对后面没有用到的编码(128-255)表示自己国家的语言,并加上了其它的相关的符号,直到编码空间被全部用完,从128-255的字符集称为“ASCII的扩展字符集”。

汉字怎么办?

  等到中国人使用电脑的时候,发现已经没有编码供我们来存储对应的汉字了,连扩展的空间都已经被全部占满了。所以我们的前辈们用自己的智慧创造性提出了新的编码格式:


 1. 去除127之外的乱七八糟的字符串和符号    

 2. 如果一个字节且小于127号的字符,与原ASCII码意义相同    

 3. 如果有两个同时大于127的字符则表示一个汉字,所以就会有一个字符会占用两个字节的说法
阅读更多

说说.Net与Java中的字符串

Java字符串碰到的问题

在写Java程序碰到一个问题,而正是这个问题引发了我对字符串的思考,Java示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

public void TestStr(String success)
{

if(success=="Y"){
System.out.println("Equal");
}
else
{
System.out.println("Not Equal");
}

}

```

上面的这个函数很简单,但会随着调用的方式的不同而显示出不同的结果:

``` Java
public void CallMethod()
{
TestStr("Y");//Equal
TestStr("YY".substring(0,1));//Not Equal
}

```

对于这样的一个结果,我们可以先思考一个问题:" == " 这个运算符的作用?

1. 对于基础数据类型而言是比较值是否相同(作用与equal相同)

2. 对于引用类型,则比较地址是否一样


但如果理解上面的代码,我们还要理解Java中字符串的机制。由于字符串是比较常用的类型,为了保证性能,所以在设计字符串的时候会有一个“池”的概念。

- 字符一旦创建成功后,就不再发生变化,字符的运算也都是创建新的字符串对象

- 字符创建前,查找内存中是否已经存在相同的字符串,如果有则直接把地址给当前的对象,没有则直接创建新对象


所以对于上面的代码,因为在开始已经创建的“Y”字符串,所以后面出生现的所有的“Y”都是引用我们当前的“Y”,所以我们就可以理解为什么第一个是打印Equal,另一个是打印Not Equal.


### .Net中如何处理

而对于.Net来说,字符串的原理大致相同,如果是相同的代码,但运算的结果是与Java不一样的:

![dotnet](/img/assets/14/01.png)


我们知道在.Net string也是引用类型,但当“==”作用于两个引用类型的时候,比较则是地址,但在.Net中字符比较时,比较的却是值。这个归功于.Net对“==”的重载,[string源码](http://referencesource.microsoft.com/#mscorlib/system/string.cs,8281103e6f23cb5c){:target="_blank"}。如果想比较地址,则使用 object.ReferenceEquals()这个函数。


``` C#

public static bool operator == (String a, String b)
{
return String.Equals(a, b);
}

```

对于.Net运算符重载的这个动作,个人觉得更贴近日常的使用习惯,因为在编码的过程中,字符串中绝大多数的使用场景都是值,而不是引用。而对Java而言,保证的运算的原汁原味,少了人为的封装的干扰,使用是注意区分,习惯了反而觉得更为合理。

### 几个疑问


#### 字符串是引用类型,为什么不使用new来创建对象?

字符串是一个特殊的引用对象 ,声明就是创建了一个对象,如果使用new,则会重复的创建对象(Java中可以使用new创建,.Net中则直接不允许这样操作),浪费内存,如下:

``` Java    

String str=new String("1234");

String str1="1234";

两种的定义方式相同,但是使用new的时候,又额外分配了内存空间。

字符串是引用类型,但是传参的时候却无法修改它的值?有其它的引用类型有什么不同?

  public void CallMethod(){

    String str="abc";
    AddSuffix(str);

    System.out.println(str);//打印出abc
  }

  public void AddSuffix(String x){

      x=x+"123";
  }

当我们去调用这个函数的时候,发现str的值却没有发生改变。 因为在调用AddSuffix 函数时,str把自己作拷贝成一个副本传递给形参x,当对x赋值的时候,系统重新创建了一个字符对象,把引用的地址给x,此处是重新创建对象,而不是修改原来的字符串对象(字符串不可更改)。两种方式示意如下:

字符串

字符串

阅读更多

linux下sublime如何使用中文

原来在使用linux的时候最大的诟病是在sublime text下面不能写中文,各种百度和搜索都没能解决,但现在又重新下linux下面做开发,又要重新面对这个问题,好在问题已经有了很好的解决方案。

使用方法

  • 首先更新你的系统 :

    
    sudo apt-get update && sudo apt-get upgrade
    
  • 选择一个目录后,用git clone 下面地址:

    
    git clone https://github.com/lyfeyaj/sublime-text-imfix.git
    
  • 使用命令进入sublime- text- imfix 路径 :

    
    cd sublime-text-imfix
    
  • 运行以下脚本

  ./sublime-imfix
  • 完成后 重启电脑。

    解决Ubuntu下Sublime Text 3无法输入中文

阅读更多

jekyll如何使用中文路径

出现问题

最近在使用jekyll在本地预览自己写的博客无法正常打开,而提交到github上却可以正常解析。看了一下发现是文件写的博客有什么变化,原来是因为博客的markdown文件使用了中文文件名,jekyll无法正常解析出现乱码。

解决方法:

修改安装目录\Ruby22-x64\lib\ruby\2.2.0\webrick\httpservlet下的filehandler.rb文件,建议先备份。找到下列两处,添加一句(+的一行为添加部分)


    path = req.path_info.dup.force_encoding(Encoding.find("filesystem"))
    + path.force_encoding("UTF-8") # 加入编码
    if trailing_pathsep?(req.path_info)

    break if base == "/"
    + base.force_encoding("UTF-8") #加入編碼
    break unless File.directory?(File.expand_path(res.filename + base))

修改完重新jekyll serve即可支持中文文件名。

阅读更多

多线程如何排队执行

场景

有一个这样场景,程序会有一个非常耗时的操作,但要求耗时的操作完成后,再顺序的执行一个不耗时的操作,而且这个程序的调用,可能存在同时调用的情况。

具体的模型如下:

moxing

从Start开始触发了5个线程,经过一个longTimeJob同时执行,我们不关心longJob的执行时间和先后顺序,根据Start的先后顺序来执行一个ShortJob。下面我们用代码来模拟上面的过程。

举例说明:有ABCD 4个线程,进入的顺序也是ABCD,A耗时3s,B耗时7s,C耗时1s,D耗时3s. 所以如果当4个线程都同时开始执行时,完成的先后顺序为 CADB,但我们要求的顺序是ABCD,也就是说C要等待AB执行完后,才能继续后续的工作。

我们可以用请求bing搜索来模拟longTimeJob,根据传入的序列来决定请求多少次,主要模拟方法如下:


    private static async Task Test()
    {
        var arry = new[]
        {
            10, 9, 8, 7, 6, 5, 4, 3, 2, 1
        };
        var listTask = new List<Task<int>>();
        foreach (var i in arry)
        {
            var i1 = i;
            var task = Task.Run(() => DoJob(i1));

            listTask.Add(task);
        }

        foreach (var task in listTask)
        {
            Console.WriteLine("输出-->:" + await task);//
        }
    }     

    public static Task<int> DoJob(int o)
    {
        return Task.Run(() =>
        {
            DoLongTimeThing(o);
            return o;
        });
    }      

    public static void DoLongTimeThing(int i)
    {
        Console.WriteLine("执行-->:" + i);
        for (int j = 0; j < i; j++)
        {
            HttpGet("http://cn.bing.com/");
        }

        Console.WriteLine("执行完毕-->:" + i);
    }

    public static string HttpGet(string url)
    {
        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "GET";

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
            string content = reader.ReadToEnd();
            return content;
        }
        catch (Exception e)
        {
            return e.Message;
        }

    }

执行结果:

taskjob

阅读更多

docker 入门与安装

Docker的概念

什么是Docker

Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、bare metal、OpenStack 集群和其他的基础应用平台。

Docker的优势

对于开发和运维来说,把程序部署到生产的时候,最常见的问题是环境问题,由于服务器单机的差异,可能会导致问题比较众多烦杂。对于这个问题,docker的优势就可以体现出来了。我们假设一个系统有四个要素组成:应用app,app依赖的类库,配置文件和系统环境。

  • 对于传统的部署

    我们需要对以上个因素进行单独的考虑和配置,如果集群则面临了大量的工作量,如果使用虚拟机的快照,也过于庞大

  • docker部署 docker本身是跨平台,镜像中包含应用程序中所需要的类库和环境,一次生成多处运行。即使不跨平台的语言,只要能够运行在docker容器中,就能够实现跨平台。

Docker 安装与使用

Docker的安装

对于docker的安装可以使用以下命令:


  $ sudo apt-get install docker
阅读更多

js如何操作本地程序

背景

假设有这样一个产品,一个web和一个winform客户端,在客户在web的网页上面点击启动客户端来处理,这个时候开始调用本地的客户端,来完成指定的工作。这种场景在日常的上网中也比较常见,如使用迅雷下载。当然实现的方式也有很多种,今天我来演示一种用监控Http请求来实现这个功能,思路如下:

jsApp

HttpListener

对于上面的分析,最重要的功能虽实现对Http的监控,而.net中已经封装了我们的需求,下面看下如何具体的实现:

   static void Main(string[] args)
    {
        HttpListener listerner = new HttpListener();

        try
        {
            listerner.AuthenticationSchemes = AuthenticationSchemes.Anonymous;//指定身份验证 Anonymous匿名访问
            listerner.Prefixes.Add("http://localhost:8080/Service/");
            listerner.Start();
        }
        catch (Exception ex)
        {
            Console.WriteLine("无法启动监视:" + ex.Message);
        }

        Task.Factory.StartNew(() =>  //使用一个线程对监听
        {
            while (true)
            {
                HttpListenerContext ctx = listerner.GetContext();
                Task.Factory.StartNew(TaskProc, ctx);//回调函数,开启新线程进行调用,不影响下次监听
            }
        });

        Console.ReadKey();
    }

实现请求的响应

现在我们可以拿到请求的上下文的信息ctx,先定义一个参数的格式,简单的定义如下:

    public class ReciveInfo
    {
        public string path { get; set; }//应用程序所在的路径

        public string name { get; set; }//应用程序名称
    }

下面对ctx的Response数据进行填写.

阅读更多

win10移除Hyper

win10碰到的问题

win10 自带的Hyper与Vmare冲突,使用控制面板去除Hyper之后,win10会自动更新把Hyper又重新安装上了。。。经历几次折腾最终还是不行。原因:Hyper-V后VMware都要独占基于CPU等底层硬件的 Hypervisor才能运行,所以二者不能在同一台电脑中同时运行

修改启动项

  1. 以管理员身份运行命令提示符

  2. 在命令提示符窗口中输入以下命令

    
        bcdedit /copy {current} /d "Windows 10 (关闭 Hyper-V)"
    

运行后会提示你已经创建了另外一个启动菜单项,记下 { } 中的那串代码。

  1. 然后继续输入并运行以下命令

    
       bcdedit /set {你记下的那串代码} hypervisorlaunchtype OFF
    

在启动的时候选择”Windows 10 (关闭 Hyper-V)” 这个启动选项就可以使用Vmare了

阅读更多

爬取菜鸟裹裹的数据

菜鸟裹裹{:target=”_blank”}是阿里旗下的一个物流数据的整合平台,数据准确、及时.前几天在关注菜鸟和顺丰的争端,因为在前一天我刚刚爬到菜鸟上面的快递数据,第二天看到二者出现了摩擦,在菜鸟上面已经查不到顺丰的信息了,还好有国家邮政局出面了解决,不得不为我们是社会主义点个赞。这次爬数据经历点波折,个人觉得阿里做的安全性还是很专业的。下面开始介绍如何找到突破口把数据拿到的。



声明:此文只做技术交流,请不要恶意攻击,当然我也相信阿里的技术,不可能轻意被攻破的。


本文Demo下载:

菜鸟裹裹Demo(可能已经不能用)
快递100数据Demo

阅读更多

推荐一个jekyll博客模板

本人用的模板是基于Codeboy的博客模板改造模板{:target=”_blank”},(由于本人可能会有很多样式修改,所以不再将修改pullrequst到原项目,在此对codeboy模板表示感谢)。功能改造如下:

添加微信支付宝打赏

这里也是一个开源的项目,项目地址,使用很方便,直接引用到项目中,配置下就可了:

<script>
window.tctipConfig = {
        staticPrefix:   "http://static.tctip.com",
        buttonImageId:  1,  
        buttonTip:  "zanzhu",
        list:{
            alipay: {qrimg: "http://blog.laofu.online/img/assets/o_zhifubao.png"},
            weixin:{qrimg: "http://blog.laofu.online/img/assets/o_weixin.png"}, 
        }
};
</script>

<script src="http://static.tctip.com/js/tctip.min.js"></script>

weixin

百度流量监控

为了查看个人的博客的人气,添加了百度的统计模块,可以方便的看到博客的pv/uv.注册地址{:target=”_blank”}

static

具体的添加方式如下 :

  1. 在_incluides文件夹下添加一个baidu_analyze.html的文件,内容如下

     
    	{%if site.baidu_analyze %}
    	
    
    	{% endif %}
    	
    

    {{site.baidu_analyze}} 是一个变量,可以把你申请的baidu的key值作为_config.yml的配置值存储下来。

阅读更多