0%

说到正则,可能很多人会很头疼这个东西,除了计算机好像很难快速的读懂这个东西,更不用说如果使用了。下面我们由浅入深来探索下正则表达式:

ps:此文适用于还有没有入门正则表达基础的读者

正则表达式可以简的定义成为一种字符串的匹配方式,至于来源可以参考:正则表达式{:target=_blank}

简单的使用

有这么一段字符串ABC12345ABC1234AB12C,对于这个字符串,如果想提取其中的字母,应该怎么办呢?

1
2
3
4
5
6
1. 可以找出所有的字母列表组成一个数组,[A,B,C...Z]     

2. 把字符串转成字符的数组,进行遍历

3. 如果是字母则继续,如果不是则直接继续下一个匹配

以上的分析过程则大概的讲述了不用正则表达式的过程,如果使用正则,怎么去写呢?

首先,我们是要匹配字母,那我要知道正则中用什么来表式字母呢?

1
2
3
4
5
6
7
8

[a-z] //匹配所有的小写字母
[A-Z] //匹配所有的大写字母
[a-zA-Z] //匹配所有的字母
[0-9] //匹配所有的数字
[0-9\.\-] //匹配所有的数字,句号和减号
[ \f\r\t\n] //匹配所有的白字符

阅读全文 »

SpringMVC 概述

   Spring 是目前比较流行的MVC框架,让POJO处理起来变的容易,也支持Rest的Url请求。采用松散的耦合可插拔的接口,比其它MVC接口更具有扩展性和灵活性

maven+spring+Idea 实现helloworld

下面就让我们用maven+Spring+Idea 实现一个 helloWorld的程序(至于环境的搭建可以直接到网上找个教程)

添加Maven项目

  1. 选择maven-archetype-webapp 这个项目类型

    maven创建

  2. 填写GroupId和ArtifactId后直接下一步直到创建完成

    Group

  3. Maven生成的目录如下:

    MVN_Index

添加SpringMVC引用

对于MVC的使用,我们首先需要添加对SpringMVC的引用,使用Maven可以方便的实现对jar包的引用和版本的管理。

  1. 添加SpringMVC的引用

    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
        <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.2.RELEASE</version>
    </dependency>
    ```



    2. 添加对jsp的页面解析 jstl的引用

    ``` xml
    <dependency>
    <groupId>Javax.servlet</groupId>
    <artifactId>Javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
    </dependency>
    <dependency>
    <groupId>Javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
    </dependency>
    ```

    #### 添加SpringMVC配置

    1. 添加Spring的配置文件,修改WEB-INF下面的web.config,添加如下内容

    ``` xml

    <!-- 配置DispatcherServlet -->
    <servlet>
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置DispatcherServlet ,配置SpringfMVC配置文件的位置和名称-->
    <!--这里可以不用通过contextConfigLocation来配置SpringMVC的配置文件,可以使用默认的配置文件的目录:/WEB-INF/<servlet-name>-servlet.xml-->
    <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>
    <!--对应的Mapping-->
    <servlet-mapping>
    <servlet-name>spring-mvc</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
  2. Spring文件配置MVC,在resources文件夹下面添加对应的spring-mvc.xml,添加如下内容:

     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
         <property name="redirectContextRelative" value="true"></property>
         <property name="prefix" value="/WEB-INF/views/"></property>
         <property name="suffix" value=".jsp"></property>
     </bean>
     <!--配置扫描的包-->
     <context:component-scan base-package="Controller"></context:component-scan>
    
阅读全文 »

一直都想给自己的博客添加一个浮动的目录,在网上也找也几个,从易用性方面都不是太理想,所以今天才有了想法自己去写一个插件 。

需求


 1. 当打开博客的时候在右下角自动生成对应的目录  

 2. 支持拖拽移动  

 3. 可以点击展开和收缩  (目前未实现)

易用性方面,希望能够直接引用 js后,来执行一句代码来完成对应的动作 。

实现逻辑


  1. 读取页面的所有h1,h2,h3,h4,h5

  2. 根据对应的元素和排序,生成对应的数据,格式如下:

      [
        {
            text: "目录",
            level: 2,
            achorName: "目录",
            order: 1,
            chapterIndex: "1"
        }, {
            text: "UTF8的出现",
            level: 3,
            achorName: "utf8的出现",
            order: 6,
            chapterIndex: "1.5"
        }
    ]
    
  3. 根据数据生成对应的html

    CataLog

相关使用

代码地址:ICatalogJs

使用时候只需要引用js后,执行init方法:

阅读全文 »

目录

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的字符则表示一个汉字,所以就会有一个字符会占用两个字节的说法
阅读全文 »

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

解决方法:

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

1
2
3
4
5

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,根据传入的序列来决定请求多少次,主要模拟方法如下:

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

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

Docker的优势

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

  • 对于传统的部署

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

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

Docker 安装与使用

Docker的安装

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

1
2
3

$ sudo apt-get install docker

阅读全文 »

背景

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

jsApp

HttpListener

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

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
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,先定义一个参数的格式,简单的定义如下:

1
2
3
4
5
6
7
8
public class ReciveInfo
{
public string path { get; set; }//应用程序所在的路径

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


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

阅读全文 »