目录
一、正则表达式
1.概述
正则表达式是用来描述具有一定特征的字符串的特殊字符串。
2.元字符与转义
3.字符类
1)自定义
由[]组,只匹配一个,需要注意以下四个:
- ^ 如果在第一个位置,表示取反的含义
- - 表示一个区间即范围
- ] 最近一个位置为:结束,如果要表示普通的]请加\转义
- .在字符类中是代表任意的字符,如果要代表自身.的含义需挪动位置或者\ .
[ae134] -> a e 1 3 4
[(as)] ->a s ( )
[a-z] ->小写字母
[-\]a-z\[] -> -[] 及小写字母
2)默认|标准字符类
h[ea]llo –>hello hallo
h(e|a)llo ->hello hallo
[\-\\abc] -> - \ a b c
\d\s ->一个数字和一个空白
[\d\s] –> 数字或空白
4.量词
匹配的过程中,需要指定次数
co*ke–>不限个数的O
co+ke–>至少一个O
co?ke->1个或零个O
co{0}ke->0个
co{5,}ke–>5次及以上
co{5,8}ke–>至少5次,最多8次
[1-9]\d{3} –>大于等于1000小于等于9999的数
[1-9]\d{2,4} –>大于等于100小于等于99999的数
1[34578]\d{9} : 匹配手机号
<[a-zA-Z]+\d?>->网页标签
<[A-Za-z][A-Za-z0-9]*>->网页标签
5.贪婪模式
在匹配次数不定时如* {n,} +,匹配字符越多越好,默认模式即”贪婪模
- 贪婪模式 greedy(匹配字符越多越好,可回溯)
- ?懒惰模式 lazy reluctant (匹配字符越少越好,可回溯)
- +独占模式 possessive(匹配字符越多越好,不可回溯) 用的较少 cokecolacoooooooooooooke
.*o –>贪婪模式
.{2,}o–>贪婪模式
.{2,}?o –>懒惰模式
.{2,}+o –>独占模式,不可回溯没有匹配到内容。
<.+?> ->找出标签不要标签内的内容。不是<.+>
<[^>]+>->找出标签不要标签内的内容。不是<.+>
阻止贪婪有两种方式:
- 量词后面使用
- 使用取反
6.边界
- 边界不占用宽度,只是一个界限
- ^ 开始 ,\b 单词边界,\B 非单词边界,$ 结束
- ^ 多行代表每行头单行代表整个字符串的开始
- $ 多行代表每行尾单行代表字符串的结尾
- \b 匹配前面或后面的不是\w
- \B 匹配前面或后面的是\w
查找开头的hello->^hello
找出独立的单词world->\bworld\b
查找结尾的world->world$
7.选择符与分组
1)选择符
- | ->优先级低 ,满足匹配则停止,不会查找更优的方案
- he|hello –>只匹配 he,不匹配 hello
- hello|he->匹配 he 与 hello
2)分组
匹配abc->ab|c
匹配abac->a(b|c)
只匹配get->\bget\b
匹配get和getValue->getvalue|getget(value)?
获取andor->\band\b|\bor\b\b(and|or)\b
反向引用:内部默认缓存,从第一个左括号计算,编号为 1 开始。
必须认识组编号,为(的位置
(")test\1 –> “第 1 个左括号中
((")test)\2 –> “第 2 个左括号中
((("))test2)\3 –> “第 3 个左括号中
["'](.*?)["'] -> 错误的找出合法的字符串""或"
(["'])([^"']+)\1 ->找出合法的字符串""或"
非捕获组:(?:xxx) :不缓存组:
(["'])(?:[^"']+)\1 ->不缓存第二组,不能引用第二组
(?:["'])(?:[^"']+)\1 –>所有的组都没有缓存,不能再引用了。
找出合法的标签:
<(b)>(?:[^<]+)</\1> -> <b>13321</b>
<([a-zA-Z]([a-zA-z]{1,5}|\d{1,2})?)>(?:[^<]+)</\1> -->找出合法的标签
3)模式修改符
- i:insensitive 使正则表达式对大小写不敏感;(重点)
- s:singleline 开启“单行模式”,即点号“.”匹配新行符
- m:multiline 开启“多行模式”,即“^”和“$”匹配新行符的前面和后面的位置
(?i)select(?-i) -> 不区分大小写。
8.零宽断言
前瞻(Lookahead)后顾(Lookbehind)
(\w+)(?<=ing) –>匹配singingtesting整个单词->后顾 (\w+)(?=ing) -->匹配singtest->前瞻
二、正则表达式在java中的应用
1.常用类
java.util.regex Pattern Matcher String
一般在查找、替换、分割、组的使用
1)Pattern
2)Matcher
3)字符串与正则
/**
* Pattern: 模式 -> 将普通的字符串赋予正则的含义
* Matcher: 匹配 -> 正则和测试的字符串
*/
public class Regex001 {
public static void main(String[] args) {
//定义一个字符串
String str = "shxst11shxst22shsxt";
//转成正则表达式
Pattern p = Pattern.compile("\\d{2}");
//匹配
Matcher m = p.matcher(str);
System.out.println(m.find());// 有没有满足的字串 true
System.out.println(m.group());// 获取找到的内容 11
System.out.println(m.find());//true
System.out.println(m.group());//22
str = "abcshsxt11shsxt22shsxt";
p = Pattern.compile("[a-zA-Z0-9]+");
m = p.matcher(str);
// 判断字符串是否满足现在的描述
System.out.println(m.matches());//true
String str1 = "abcshsxt1shsxt2shsxt";
str1 = str1.replaceAll("\\d","-");
System.out.println(str1);//abcshsxt-shsxt-shsxt
}
}
三、网络编程
1.网络分层
1)通信协议的分层
2)IP位置
( IP)是 Internet Protocol 的外语缩写,网络之间互连的协议也就是为计算机网络相互连接进行通信而设计的协议。在因特网中,它是能使连接到网上的所有计算机网络实现相互通信的一套规则,规定了计算机在因特网上进行通信时应当遵守的规则。任何厂家生产的计算机系统,只要遵守 IP 协议就可以与因特网互连互通。
端口:区分数据流向的软件 0-65535 不要使用 1024 以下的端口,每一个协议拥有自己的端口,在同一个协议下端口不能重复 FTP:21 HTTP:80
/**
* InetAddress -> 计算机的抽象 ip地址
*/
public class Net001 {
public static void main(String[] args) throws Exception{
//获取本机
InetAddress address = InetAddress.getLocalHost();
System.out.println(address);//DESKTOP-VENJN9K/192.168.11.113
// 局域网中的计算机名,域名,ip地址
address = InetAddress.getByName("LAPTOP-R2CRGT23");//里面还可以创ip地址
System.out.println(address);//LAPTOP-R2CRGT23/192.168.11.115
// 获取外网中的电脑
address = InetAddress.getByName("www.baidu.com");
System.out.println(address);//www.baidu.com/180.101.49.12
}
}
常用命令
- 查看本机IP地址,在控制台输入:
ipconfig
- 检查网络是否连通,在控制台输入:
ping 空格 IP地址
ping 220.181.57.216
特殊的IP地址
- 本机IP地址:
127.0.0.1
、localhost
3)端口(port)和url
端口是虚拟的概念,并不是说在主机上真的有若干个端口。通过端口,可以在一个主机上运行多个网络应用程序。可以类比为:IP 相当于公司,端口相当于公司各部门,URL,相当于各部门的人员
URL全称是Uniform Resource Location,也就是统一资源位置。实际上,URL就是一种特殊的URI,它除了标识一个资源,还会为资源提供一个特定的网络位置,客户端可以通过它来获取URL对应的资源。
4)网络爬虫原理
public class Demo003 {
public static void main(String[] args) throws Exception {
URL url = new URL("http://www.baidu.com:80/index.html");
BufferedInputStream bis = null;
File file = new File("baidu.html");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
try {
bis = new BufferedInputStream(url.openStream());
int len ;
byte[] car = new byte[1024];
while((len=bis.read(car))!=-1){
bos.write(car,0,len);
}
bos.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
bis.close();
bos.close();
}
}
}
2.传输层协议
1) 协议
TCP:TCP(transfer control protocol) 打电话面向连接、安全、可靠,效率低
UDP:UDP(UserDatagramProtocol ) 发送短信非面向连接、不安全、数据可能丢失、效率高
2)UDP编程: DatagramSocket DatagramPacket
UserDatagramProtocol,一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。其特点为:非面向连接;传输不可靠;数据可能丢失。
/**
* 接收端:
* DataGramSocket 工具 指定自己的端口 8866
* byte[] 存放数据容器
* DatagramPacket
*
*/
public class Receive001 {
public static void main(String[] args) throws Exception{
// 我在8866等着
DatagramSocket socket = new DatagramSocket(8866);
//
byte[] car = new byte[1024];
// 一会儿接收到的数据 就放在car,最多能接受 car.length
DatagramPacket packet = new DatagramPacket(car,car.length);
//接收
socket.receive(packet);
// 获取真实接收到的数据的长度
int len = packet.getLength();
String str = new String(car,0,len);
System.out.println(str);
socket.close();
System.out.println("我接受完了");
}
}
/**
* 发送端
* DatagramSocket 工具 指定自己的端口 8899
* data 发送的数据
* DatagramPacket 指定接收者的ip 端口
* send
*/
public class Send001 {
public static void main(String[] args) throws Exception {
// 工具
DatagramSocket socket = new DatagramSocket(8899);
// hello world
byte[] data = "hello world".getBytes();
// 将什么数据发送给谁的哪个端口
DatagramPacket packet = new DatagramPacket(data,0,data.length,InetAddress.getLocalHost(),8866);
socket.send(packet);
System.out.println("我的数据发送完了");
socket.close();
}
}
3)TCP编程:ServerSocket Socket
TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。
两端通信时步骤:
- 服务端程序,需要事先启动,等待客户端的连接。
- 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。
在Java中,提供了两个类用于实现TCP通信程序:
- 客户端:
java.net.Socket
类表示。创建Socket
对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。 - 服务端:
java.net.ServerSocket
类表示。创建ServerSocket
对象,相当于开启一个服务,并等待客户端的连接。
4)实现步骤
- 【服务端】启动,创建ServerSocket对象,等待连接。
- 【客户端】启动,创建Socket对象,请求连接。
- 【服务端】接收连接,调用accept方法,并返回一个Socket对象。
- 【客户端】Socket对象,获取OutputStream,向服务端写出数据。
- 【服务端】Scoket对象,获取InputStream,读取客户端发送的数据。
到此,客户端向服务端发送数据成功
自此,服务端向客户端回写数据。
- 【服务端】Socket对象,获取OutputStream,向客户端回写数据。
- 【客户端】Scoket对象,获取InputStream,解析回写数据。
- 【客户端】释放资源,断开连接。
/**
* 服务端
* ServerSocket -> 指定自己在哪个端口等待别人主动连接
* accept -> 阻塞等待的过程
* Socket 和当前客户端的连接
* inputStream -> 接收数据
* outputStream -> 发送数据
*/
public class Server001 {
public static void main(String[] args) throws Exception{
//指定自己在哪个端口等待别人主动连接
ServerSocket server = new ServerSocket(9988);
//阻塞等待的过程
Socket client = server.accept();
System.out.println("有客户端来了");
//接收数据
BufferedInputStream bis = new BufferedInputStream(client.getInputStream());// 读数据 源头是客户端
//发送数据
BufferedOutputStream bos = new BufferedOutputStream(client.getOutputStream()); // 写数据 目的地是客户端
//接收的数据
byte[] car = new byte[1024];
int len = bis.read(car);
System.out.println("我从客户端接收到: "+new String(car,0,len));
//发送的数据
bos.write("我已经收到你的消息了".getBytes());
bos.flush();
bis.close();
bos.close();
client.close();
}
}
/**
* 客户端
* Socket 服务端的ip和端口
* inputStream -> 接收数据 服务端
* outputStream -> 发送数据 服务端
*
*/
public class Client001 {
public static void main(String[] args) throws Exception{
//创建对象同时就是在创建连接, 其中包含了三次握手
Socket serverInfo = new Socket(InetAddress.getLocalHost(),9988);//这里拿的是自己的地址,也可以拿别人的地址getByName("192.168.11.168")
//创建流
BufferedInputStream bis = new BufferedInputStream(serverInfo.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(serverInfo.getOutputStream());
//发送数据
bos.write("hello server".getBytes());
bos.flush();
System.out.println("信息发送完成");
//接收数据
byte[] car = new byte[1024];
int len = bis.read(car);
System.out.println("我从服务端接收到的数据:" + new String(car,0,len));
bos.close();
bis.close();
serverInfo.close();
}
}
四、手写聊天室
/**
*服务器端
*/
public class ChatRoom001 {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(8889);
while(true){
System.out.println("等待");
Socket client = server.accept();
// 开启一个线程专门发送消息
new Thread(new SendThread(client.getOutputStream())).start();
// 开启一个专门接收消息的线程
new Thread(new ReceiveThread((client.getInputStream()))).start();
}
}
}
class SendThread implements Runnable{
private OutputStream os;
public SendThread(OutputStream os) {
this.os = os;
}
@Override
public void run() {
Scanner sc = new Scanner(System.in);
// 循环地发送数据
while(true){
System.out.println("请输入要发送的数据:");
String msg = sc.nextLine();
try {
os.write(msg.getBytes(),0,msg.getBytes().length);
os.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class ReceiveThread implements Runnable{
private InputStream is;
public ReceiveThread(InputStream is) {
this.is = is;
}
@Override
public void run() {
// 一直循环接收客户端的数据
while(true){
byte[] data = new byte[1024];
int len ;
try {
len = is.read(data);
System.out.println(new String(data,0,len));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 客户端
*/
public class ChatRoom002 {
public static void main(String[] args) throws Exception {
Socket serverInfo = new Socket(InetAddress.getByName("192.168.11.168"),8889);
// 开启一个线程专门发送消息
new Thread(new SendThread(serverInfo.getOutputStream())).start();
// 开启一个专门接收消息的线程
new Thread(new ReceiveThread((serverInfo.getInputStream()))).start();
}
}