

public static void main(String[] args) {
// 匹配
String regex = "\\d+";
String content1 = "123";
System.out.println(content1.matches(regex)); // true, 因为"123"完全由数字组成
// 替换
String content2 = "123,avc,$%#";
System.out.println(content2.replaceAll(regex, "")); // ",avc,$%#", 将所有数字替换为空字符串
System.out.println(content2.replaceFirst(regex, "")); // ",avc,$%#", 将第一个数字序列替换为空字符串
// 分割
String content3 = "123,asd,#$,456";
System.out.println(content3.split("[^0-9]+").toString()); // 打印的是数组对象的内存地址, 如"[Ljava.lang.String;@15db9742"
// 分组
final Pattern cp1 = Pattern.compile("([a-z]+.*?\\d+)");
final Pattern cp2 = Pattern.compile("([a-z]+):(\\d+)");
String scores = "java:88,mysql:a99,hadoop:82,spark:91";
final Matcher mt1 = cp1.matcher(scores);
while (mt1.find()){
final String score = mt1.group(0);
final Matcher mt2 = cp2.matcher(score);
if(mt2.find()){
System.out.println(mt2.group(1) + "->" + mt2.group(2)); // "java->88", "hadoop->82", "spark->91"
}
}
}
// 初始化正则表达式
val regexStr: String = "\\d+"
val regex: Regex = regexStr.r
// 字符串匹配
val content = "123"
println(content.matches(regexStr)) // 输出:true
// 字符串分割
val content4 = "123,87,xy,921"
content4.split("[^0-9]+").foreach(println) // 输出分割后的数字:123, 87, 921
// 字符串替换
// 替换字符串中的第一个匹配项:
val content3 = "123,87,xy,921"
println(regex.replaceFirstIn(content3, "66")) // 输出:66,87,xy,921
// 替换所有符合正则的对象,匹配到就替换,没有匹配到就不替换,返回类型是Option[String]
println(regex.replaceSomeIn(content3, mat => Some((mat.group(0).toInt + 1).toString)))
// 替换所有符合正则的对象,匹配到就替换,没有匹配到就不替换,返回类型是String
println(regex.replaceAllIn(content3, mat => (mat.group(0).toInt + 1).toString))
// 模式匹配
val content = "123,456,789"
val regex = "(\\d+),(\\d+),(\\d+)".r
println(content match {
case regex(a, b, c) => (a.toInt + 1, b.toInt + 1, c.toInt + 1)
})// 如果content2符合regex2的模式,regex2(a,b,c,d)会提取四个字符串,并且存放到变量a,b,c,d中;匹配成功后,将这四个字符串变量转换为整数+1。
// 分组
val pat = "([a-zA-Z]+):(\\d+)".r // 边界(粗略提取整体)
val patIn = "([a-zA-Z]+):(\\d+)".r // 正则构成(提取细则)
val scores = "java:88,mysql:99,hadoop:82,spark:91";
// 提取第一个符合正则的对象
val opt: Option[String] = pat.findFirstIn(scores)
println(opt.get) // java:88
// 提取所有符合正则的对象
val it: Regex.MatchIterator = pat.findAllIn(scores)
println(it.mkString(",")) // 输出:java:88,mysql:99,hadoop:82,spark:91
// 提取第一个符合正则的对象,且该对象可以按组匹配
val mat: Option[Regex.Match] = patIn.findFirstMatchIn(scores)
val str: String = mat.get.group(1)
val str2: String = mat.get.group(2)
println(str + ":" + str2)// 输出:java:88
// 提取出所有符合正则且可按组匹配的对象构成一个迭代器
val mats: Iterator[Regex.Match] = patIn.findAllMatchIn(scores)
mats.map(m=>{
val subject: String = m.group(1)
val score: String = m.group(2)
(subject,score)
}).foreach(println)// 依次输出:(java,88), (mysql,99), (hadoop,82), (spark,91)
现有如下日志信息,请使用scala正则表达式解析如下信息:
日志级别
日期
请求URI
INFO 2016-07-25 requestURI:/c?app=0&p=1&did=18005472&industry=469&adid=31 INFO 2016-07-26 requestURI:/c?app=0&p=2&did=18005473&industry=472&adid=31 INFO 2016-07-27 requestURI:/c?app=0&p=1&did=18005474&industry=488&adid=32
val logs = "INFO 2016-07-25 requestURI:/c?app=0&p=1&did=18005472&industry=469&adid=31\n" +
"INFO 2016-07-26 requestURI:/c?app=0&p=2&did=18005473&industry=472&adid=31\n" +
"INFO 2016-07-27 requestURI:/c?app=0&p=1&did=18005474&industry=488&adid=32"
val pat = "(INFO|WARN|ERROR) ([0-9]{4}-[0-9]{2}-[0-9]{2}) requestURI:(.*)".r
val it = pat.findAllMatchIn(logs)
it.map(m=>{
val level: String = m.group(1)
val date: String = m.group(2)
val uri: String = m.group(3)
(level,date,uri)
}).foreach(println)
/* 输出:
(INFO,2016-07-25,/c?app=0&p=1&did=18005472&industry=469&adid=31)
(INFO,2016-07-26,/c?app=0&p=2&did=18005473&industry=472&adid=31)
(INFO,2016-07-27,/c?app=0&p=1&did=18005474&industry=488&adid=32)
*/
val regex = "(INFO|WARN|ERROR) (\\d{4}-\\d{2}-\\d{2}) requestURI:(.*)".r
Array(
"INFO 2016-07-25 requestURI:/c?app=0&p=1&did=18005472&industry=469&adid=31",
"INFO 2016-07-26 requestURI:/c?app=0&p=2&did=18005473&industry=472&adid=31",
"INFO 2016-07-27 requestURI:/c?app=0&p=1&did=18005474&industry=488&adid=32",
"WRONG 2016-07-26 requestURI:/c?app=0&p=2&did=18005473&industry=472&adid=31"
).collect({
case regex(level,date,uri) => (level,date,uri)
}).foreach(println)
/* 输出:
(INFO,2016-07-25,/c?app=0&p=1&did=18005472&industry=469&adid=31)
(INFO,2016-07-26,/c?app=0&p=2&did=18005473&industry=472&adid=31)
(INFO,2016-07-27,/c?app=0&p=1&did=18005474&industry=488&adid=32)
*/
val scores = "java:88,mysql:99,hadoop:82,spark:91" val regex: Regex = "([a-z]+):(\\d+)".r val it: Iterator[Regex.Match] = regex.findAllMatchIn(scores) it.foreach(mat => println(mat.group(1),mat.group(2).toInt)) /* (java,88) (mysql,99) (hadoop,82) (spark,91) */
val scores = "java:88,mysql:99,hadoop:82,spark:91"
val pat1: Pattern = Pattern.compile("([a-z]+.*?\\d+)")
val pat2: Pattern = Pattern.compile("([a-z]+):(\\d+)")
val mat1: Matcher = pat1.matcher(scores)
while(mat1.find()){
val score: String = mat1.group(0)
val mat2: Matcher = pat2.matcher(score)
if(mat2.find()){
println((mat2.group(1), mat2.group(2)))
}
}
隐式类允许你向已存在的类型添加新的方法,是一种便捷的方式在不修改源代码的情况下扩展类的功能。
// 字符串的方法扩展,而在 Java 中 String 是final的,无法扩展
implicit class StrExt(str:String){
def incr() = str.map(c=>(c+1).toChar)
def isEmail = str.matches("\\w+@[a-z0-9]{2,10}\\.(com(.cn)?|cn|edu|org)")
}
val a:String = "12665473@qq.com"
val incr: String = a.incr
val isEmail: Boolean = a.isEmail
private static void close(AutoCloseable...acs){
for (AutoCloseable ac : acs) {
if (Objects.nonNull(ac)) {
try {
ac.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
try{
// 可能抛出异常的代码块
BufferedReader reader = new BufferedReader(new FileReader("test.txt"));
System.out.println(reader.readLine());
} catch(IOException ex) {
// 异常的捕获和处理
System.err.println("An IOException occurred: " + ex.getMessage());
} finally{
// 无论是否发生异常,都会执行的代码块,通常用于释放资源
close(reader);
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter("test.txt"))) {
// 使用资源,该资源必须extends AutoCloseable
// try块中的`BufferedWriter`在代码块执行完毕后会自动关闭,不需要再通过finally关闭资源
writer.write("Hello World");
} catch (IOException ex) {
// 异常的捕获和处理
System.err.println("An IOException occurred: " + ex.getMessage());
}
try-catch-finally中finally不仅可以关闭资源,还可以用于执行其他代码块。
try-with-resources资源会立即被关闭,InputStream,OutputStream,Reader,Writer等均实现了该接口。
try-with-resources优先于try-catch-finally,因为可能会存在finally延迟。
3.2.1 异常数据类型
使用Option类型可以在函数无法返回有效结果时,返回None,而不是抛出异常。
def divideOption(a:Int,b:Int):Option[Int] = {
try {
Some(a/b)
}catch {
case _ : ArithmeticException => None
}
}
Either类型通常用于函数可能返回两种类型的结果,其中Left通常用于错误或异常,Right用于正常值。
Either[String, Int]需要包含两种数据类型的原因是需要同时兼容``Right[Nothing,Int]和Left[String,Nothing]的类型。
def divideEither(a: Int, b: Int): Either[String, Int] = {
try {
Right(a / b)
}:Right[Nothing,Int] catch {
case _: ArithmeticException => Left("divide by zero"):Left[String,Nothing]
}
}
Try 是一个代表可能会成功或失败的操作的容器类型。Success表示操作成功,Failure表示操作失败。
Failure需要一个Throwable对象作为参数。
def divideTry(a: Int, b: Int): Try[Int] = {
try {
Success(a / b)
} catch {
case _: ArithmeticException => Failure(new Exception("divide by zero"))
}
}
Option 类型:getOrElse()
Either 和 Try 类型:模式匹配
val either: Either[Int, String] = Left(404)
val errorInfo = either match {
case Left(err) => s"发生错误,错误码:$err"
case Right(value) => s"操作成功,结果为:$value"
}
// 这会返回:"发生错误,错误码:404"
import scala.util.{Try, Success, Failure}
val attempt = Try { Integer.parseInt("abc") }
val result = attempt match {
case Success(value) => s"转换成功,结果为:$value"
case Failure(ex) => s"转换失败,错误信息:${ex.getMessage}"
}
// 这会返回:"转换失败,错误信息:For input string: "abc""
3.2.2 模式匹配
try {
// 可能抛出异常的代码块
val result = 10 / 0
} catch {
// 捕获异常的格式是:case e:XxxException => ...
case ex: ArithmeticException => println("ArithmeticException occurred")
case ex: NullPointerException => println("NullPointerException occurred")
case ex: Exception => println("Other exception occurred: " + ex.getMessage)
}
import scala.util.control.Exception.allCatch def divideOpt(a: Int, b: Int) = allCatch.opt(a / b) def divideWithTry(a: Int, b: Int) = allCatch.withTry(a / b) def divideEither(a: Int, b: Int) = allCatch.either(a / b)
import scala.util.control.Exception.failAsValue def divideFail(a: Int, b: Int) = failAsValue(classOf[ArithmeticException])(-1)(a / b)
case class Text(author: String, title: String, price: Float)
class TextSon(level: String,
override val author: String,
override val title: String,
override val price: Float)
extends Text(author, title, price) {
val _level: String = level
override def toString() = s"TextSon{${super.toString}, ${_level}}"
}
添加新的属性后如何重新toString()方法?
override def toString() = s"TextSon{${super.toString}, ${_level}}"
val obj: Text = new TextSon("TOP", "The Wild Roaring", "张培元", 86.32f)
进行类型判断,检查obj是否是TextSon类型的实例
val isIns: Boolean = obj.isInstanceOf[TextSon]
进行类型转换,需要通过allCatch.opt()进行异常处理
val safeSon: Option[TextSon] = allCatch.opt(obj.asInstanceOf[TextSon])
println(opt.getOrElse("转换失败"))
