一、String INTERPOLATION(字符串插值)
①s:字符串插值
在任何字符串前加上s,就可以直接在串中使⽤变量了
字符串插值的位置也可以放表达式
②f:插值并格式化输出
插值f 可以对字符串进⾏格式化,类似printf:
在任何字符串字⾯前加上 f,就可以⽣成简单的格式化串,功能相似于其他语⾔中的 printf 函数。
③raw:对字符串不作任何变换的输出
除了对字⾯值中的字符不做编码外,raw 插值器与 s 插值器在功能上是相同的。
raw类似于s,但是raw对字符串内容不作任何的转换
object _01_StringUsage {
// 字符串插值
// s""
// f"" :
// raw"" :
def main(args: Array[String]): Unit = {
val name: String = "xiaobai"
val height: Double = 104.5
println(s"大家好, 我叫$name, 身高是:${height}cm")
println(f"大家好, 我叫$name, 身高是:${height}%.2fcm")
println(raw"大家好, 我叫$name \n 身高是:${height}cm")
}
}
二、正则表达式
Scala 通过 scala.util.matching 包中的 Regex 类来⽀持正则表达式。
scala.util.matching.Regex
- findFirstMatchIn() 返回第⼀个匹配(Option[Match])
- findAllMatchIn() 返回所有匹配结果(Regex.Match)
- findAllIn() 返回所有匹配结果(String)
findFirstIn() 和findAllIn()是最常用的两个方法
实例中使⽤ String 类的 r() ⽅法构造了⼀个Regex对象。
然后使⽤ findFirstIn ⽅法找到⾸个匹配项。
如果需要查看所有的匹配项可以使⽤ findAllIn ⽅法。
可以使⽤ mkString( ) ⽅法来连接正则表达式匹配结果的字符串,并可以使⽤管道(|)来设置不同的模式
如果需要将匹配的⽂本替换为指定的关键词,可以使⽤ replaceFirstIn( ) ⽅法来替换第⼀个匹配项,使⽤ replaceAllIn( ) ⽅法替换所有匹配项
.r
方法可使任意字符串变成一个正则表达式。
2.1正则匹配
2.2正则查找
2.3正则替换
2.4正则分组
import scala.util.matching.Regex
object _02_Regex {
// 正则表达式
// 在Scala中,使用 scala.util.matching.Regex 类描述正则
def main(args: Array[String]): Unit = {
// _01_basicMatch()
// _02_regexFind()
// _03_regexReplace()
// _04_regexUnapply()
// _05_regexUnapply()
_06_regexGroups()
}
// 1. 正则表达式基础匹配
def _01_basicMatch(): Unit = {
// 用的是String类中的matches方法
// 邮箱: xxxxx@xxxxx.xxx 需要验证 qq、126、163 邮箱
// \w{6,12}@(qq|QQ|126|163)\.(com|cn)
val emailStr: String = "shawn@163.com"
val regex: String = "\\w{4,12}@(qq|QQ|126|163)\\.(com|cn)"
println(emailStr.matches(regex))
}
// 2. 正则查找(查找一个字符串中,满足指定正则表达式规则的部分)
def _02_regexFind(): Unit = {
val str: String = "hello123world456nihao789wobuhao012"
val regex: Regex = "\\d+".r
// 查找第一个匹配项
val res0: Option[String] = regex.findFirstIn(str)
res0 match {
case Some(n) => println(n)
case _ => println("没有找到匹配项")
}
// 查找所有的匹配项
val res1: Regex.MatchIterator = regex.findAllIn(str)
while (res1.hasNext) {
println(res1.next())
}
}
// 3. 正则替换(替换一个字符串中满足条件的部分,为指定的部分)
def _03_regexReplace(): Unit = {
val str: String = "hello123world456nihao789wobuhao012"
val regex: Regex = "\\d+".r
println(regex.replaceFirstIn(str, "数字部分"))
println(regex.replaceAllIn(str, "数字部分"))
println(regex.replaceAllIn(str, matcher => {
matcher.matched match {
case "456" => "数字部分"
case _ => matcher.matched
}
// matcher.matched
// matcher.group()
// matcher.start
// matcher.end
}))
}
// 4. 正则提取器(提取的是一个字符串中,每一个分组的内容)
def _04_regexUnapply(): Unit = {
val email: String = "shawn@163.com"
// 需求: 需要提取这个邮箱的用户名部分(user)和服务部分(domain)
val regex: Regex = "(\\w{4,12})@((qq|QQ|126|163)\\.(com|cn))".r
// 注意事项:
// case后的接收数据的变量个数,要和正则中的分组的数量一致
email match {
case regex(user, domain, group3, group4) =>
println(s"user = $user, domain = $domain, group3 = $group3, group4 = $group4")
case _=> println("正则不匹配,或者分组数量匹配错误")
}
}
// 5. 提取器
def _05_regexUnapply(): Unit = {
// 需求: 需要提取这个邮箱的用户名部分(user)和服务部分(domain)
class Email(var user: String, var domain: String)
object Email {
// 提取器
def unapply(email: String): Option[(String, String)] = {
if (email.matches("\\w{4,10}@(qq|QQ|126|163)\\.(com|cn)")) {
val parts: Array[String] = email.split("@")
Some(parts(0), parts(1))
}
else
None
}
}
//
"shawn@126.com" match {
case Email(user, domain) => println(s"user = $user, domain = $domain")
case _ => println("没有提取到数据")
}
}
// 6. 正则分组
def _06_regexGroups(): Unit = {
val email: String = "shawn@163.com xiaobai@126.com xiaohui@qq.com"
val regex: Regex = "(\\w{4,12})@((qq|QQ|126|163)\\.(com|cn))".r
// 需求: 提取一个email中所有的分组
val matches: Iterator[Regex.Match] = regex.findAllMatchIn(email)
for (matcher <- matches) {
// 获取到分组的信息
val groupCount: Int = matcher.groupCount
for (i <- 1 to groupCount) {
println(s"第${i}组 ==> ${matcher.group(i)}")
}
println("-----------")
}
}
}
三、Netty
实现Netty模型的Server和Client端的通信
- 创建Server端
- 创建Client端
- 实现Server端Handler
- 实现Client端Handler
- 进⾏通信
3.1ClientHander
/**
* Netty实现客户端和服务端的通信
*
* 1. 导入Spark的包, 因为在Scala中是没有Netty的
* 2. 需要创建Server端的Handler和Client端的Handler, 用来封装数据
* 3. 需要Server端和Client端, 进行通信
*
* <dependency>
* <groupId>org.apache.spark</groupId>
* <artifactId>spark-core_2.11</artifactId>
* <version>2.2.0</version>
* </dependency>
*
* /
import io.netty.buffer.{ByteBuf, Unpooled}
import io.netty.channel.{ChannelHandlerContext, ChannelInboundHandlerAdapter}
/**
* 用于客户端的数据封装,其实是一个NIO中的Channel,数据以Buffer的形式传输
*/
class ClientHandler extends ChannelInboundHandlerAdapter {
// 发送消息的时候使用
override def channelActive(ctx: ChannelHandlerContext): Unit = {
println("客户端向服务端发送数据...")
// 要发送给服务端的数据
val msg: String = "hello, Server"
// 发送数据
ctx.writeAndFlush(Unpooled.copiedBuffer(msg.getBytes("utf8")))
}
// 从通道中读取数据, (读取服务端发送回来的消息)
override def channelRead(ctx: ChannelHandlerContext, msg: Any): Unit = {
println("读取服务端返回的数据...")
// 读取Channel中的缓冲区
val byteBuf: ByteBuf = msg.asInstanceOf[ByteBuf]
// 实例化一个字节数组,用于读取缓冲区中的数据
val bytes: Array[Byte] = new Array[Byte](byteBuf.readableBytes())
// 将缓冲区中的数据,读取到字节数组中
byteBuf.readBytes(bytes)
// 将字节转成字符串
println(new String(bytes, "utf8"))
}
override def channelReadComplete(ctx: ChannelHandlerContext): Unit = {
// 如果需要循环给Server发送消息, 在这里再次调用 channelActive 就可以了
// channelActive(ctx)
ctx.flush()
}
}
3.2 ServerHander
import io.netty.buffer.{ByteBuf, Unpooled}
import io.netty.channel.{ChannelHandlerContext, ChannelInboundHandlerAdapter}
class ServerHandler extends ChannelInboundHandlerAdapter {
// 当客户端连接到Server端的时候, 调用
override def channelActive(ctx: ChannelHandlerContext): Unit = {
println("一个客户端连接上了")
Thread.sleep(2000)
}
// 从通道中读取数据, (读取客户端发送回来的消息)
override def channelRead(ctx: ChannelHandlerContext, msg: Any): Unit = {
println("读取客户端发送的数据...")
// 读取Channel中的缓冲区
val byteBuf: ByteBuf = msg.asInstanceOf[ByteBuf]
// 实例化一个字节数组,用于读取缓冲区中的数据
val bytes: Array[Byte] = new Array[Byte](byteBuf.readableBytes())
// 将缓冲区中的数据,读取到字节数组中
byteBuf.readBytes(bytes)
// 将字节转成字符串
println(new String(bytes, "utf8"))
// 回传数据给Client
ctx.writeAndFlush(Unpooled.copiedBuffer("你好,客户端,再见!".getBytes("utf8")))
}
override def channelReadComplete(ctx: ChannelHandlerContext): Unit = {
// 如果需要循环给Server发送消息, 在这里再次调用 channelActive 就可以了
// channelActive(ctx)
ctx.flush()
}
}
3.3 NettyClient
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.bootstrap.Bootstrap
import io.netty.channel.{ChannelFuture, ChannelHandler, ChannelHandlerContext, ChannelInitializer}
import io.netty.channel.socket.nio.NioSocketChannel
class NettyClient {
// 连接到指定的服务端
def connect(host: String, port: Int): Unit = {
// 1. 配置线程组
val group: NioEventLoopGroup = new NioEventLoopGroup()
// 2. 创建一个客户端发送消息辅助类
val bootstrap: Bootstrap = new Bootstrap()
// 3. 绑定事件
bootstrap.group(group)
.channel(classOf[NioSocketChannel])
// 绑定IO事件
.handler(new ChannelInitializer[NioSocketChannel] {
override def initChannel(c: NioSocketChannel): Unit = c.pipeline().addLast(new ClientHandler)
})
// 4. 绑定端口
val future: ChannelFuture = bootstrap.connect(host, port).sync()
future.channel().closeFuture().sync()
group.shutdownGracefully()
}
}
object NettyClient {
def main(args: Array[String]): Unit = {
val client: NettyClient = new NettyClient
client.connect("127.0.0.1", 8888)
}
}
3.4 NettyServer
import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.{ChannelFuture, ChannelInitializer}
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.{NioServerSocketChannel, NioSocketChannel}
class NettyServer {
def bind(host: String, port: Int): Unit = {
// 1. 配置一个线程组
// 1.1. 服务器接收客户端连接的
val group: NioEventLoopGroup = new NioEventLoopGroup()
// 1.2. 轮询每一个客户端发送的消息
val loopGroup: NioEventLoopGroup = new NioEventLoopGroup()
// 2. 实例化一个服务端辅助类
val bootstrap: ServerBootstrap = new ServerBootstrap()
// 3. 绑定线程组、Channel、事件
bootstrap.group(group, loopGroup)
.channel(classOf[NioServerSocketChannel])
.childHandler(new ChannelInitializer[NioServerSocketChannel] {
override def initChannel(c: NioServerSocketChannel): Unit = c.pipeline().addLast(new ServerHandler)
})
// 4. 绑定端口
val future: ChannelFuture = bootstrap.bind(host, port).sync()
future.channel().closeFuture().sync()
group.shutdownGracefully()
loopGroup.shutdownGracefully()
}
}
object NettyServer {
def main(args: Array[String]): Unit = {
val server: NettyServer = new NettyServer
server.bind("127.0.0.1", 8888)
}
}