Scala 字符串
字符串是编程中最常用的数据类型之一。Scala 中的字符串基于 Java 的 String 类,但提供了更多便利的操作方法和语法糖。
字符串基础
字符串创建
scala
object StringCreation {
def main(args: Array[String]): Unit = {
// 基本字符串创建
val str1 = "Hello, World!"
val str2 = new String("Hello, World!")
// 空字符串
val emptyStr1 = ""
val emptyStr2 = String.empty
// 从字符数组创建
val charArray = Array('H', 'e', 'l', 'l', 'o')
val str3 = new String(charArray)
println(str1)
println(str2)
println(s"空字符串长度: ${emptyStr1.length}")
println(str3)
// 字符串比较
println(s"str1 == str2: ${str1 == str2}") // true (内容比较)
println(s"str1 eq str2: ${str1 eq str2}") // false (引用比较)
}
}字符串字面量
scala
object StringLiterals {
def main(args: Array[String]): Unit = {
// 普通字符串
val normal = "这是一个普通字符串"
// 包含转义字符的字符串
val escaped = "第一行\n第二行\t制表符\\"反斜杠\\""
// 原始字符串(三重引号)
val raw = """这是一个原始字符串
|可以包含换行
|和"引号"而不需要转义
|反斜杠 \ 也不需要转义""".stripMargin
// 多行字符串
val multiline =
"""SELECT name, age
|FROM users
|WHERE age > 18
|ORDER BY name""".stripMargin
println(normal)
println(escaped)
println(raw)
println(multiline)
}
}字符串插值
s 插值器
scala
object SInterpolation {
def main(args: Array[String]): Unit = {
val name = "Alice"
val age = 25
val height = 1.68
// s 插值器 - 基本用法
val greeting = s"Hello, my name is $name"
val info = s"I am $age years old and ${height}m tall"
// 表达式插值
val calculation = s"Next year I will be ${age + 1} years old"
val formatted = s"Height in cm: ${height * 100}"
println(greeting)
println(info)
println(calculation)
println(formatted)
// 复杂表达式
val numbers = List(1, 2, 3, 4, 5)
val summary = s"Numbers: ${numbers.mkString(", ")}, Sum: ${numbers.sum}"
println(summary)
}
}f 插值器(格式化)
scala
object FInterpolation {
def main(args: Array[String]): Unit = {
val name = "Bob"
val score = 85.6789
val percentage = 0.856
// f 插值器 - 格式化输出
val formatted1 = f"$name scored $score%.2f points"
val formatted2 = f"Percentage: $percentage%.1%%" // %% 表示 % 字符
// 数字格式化
val pi = 3.14159265359
val formatted3 = f"Pi to 3 decimal places: $pi%.3f"
val formatted4 = f"Pi in scientific notation: $pi%.2e"
// 字符串格式化
val formatted5 = f"Name: $name%10s" // 右对齐,宽度10
val formatted6 = f"Name: $name%-10s|" // 左对齐,宽度10
println(formatted1)
println(formatted2)
println(formatted3)
println(formatted4)
println(formatted5)
println(formatted6)
}
}raw 插值器
scala
object RawInterpolation {
def main(args: Array[String]): Unit = {
val path = "C:\\Users\\Alice\\Documents"
// raw 插值器 - 不处理转义字符
val rawString = raw"Path: $path\nThis \t will \\ not \\ be \\ escaped"
val normalString = s"Path: $path\nThis \t will \\ be \\ escaped"
println("Raw interpolation:")
println(rawString)
println("\nNormal interpolation:")
println(normalString)
// 正则表达式中很有用
val regex = raw"\d{3}-\d{2}-\d{4}" // 不需要双重转义
println(s"Regex pattern: $regex")
}
}字符串操作
基本操作
scala
object BasicStringOperations {
def main(args: Array[String]): Unit = {
val str = "Hello, Scala World!"
// 长度和索引
println(s"Length: ${str.length}")
println(s"First character: ${str(0)}")
println(s"Last character: ${str(str.length - 1)}")
// 子字符串
println(s"Substring(0, 5): ${str.substring(0, 5)}")
println(s"Substring(7): ${str.substring(7)}")
// 查找
println(s"Index of 'Scala': ${str.indexOf("Scala")}")
println(s"Last index of 'l': ${str.lastIndexOf('l')}")
println(s"Contains 'World': ${str.contains("World")}")
// 大小写转换
println(s"Uppercase: ${str.toUpperCase}")
println(s"Lowercase: ${str.toLowerCase}")
// 去除空白
val paddedStr = " Hello, World! "
println(s"Trimmed: '${paddedStr.trim}'")
// 替换
println(s"Replace 'World' with 'Scala': ${str.replace("World", "Scala")}")
println(s"Replace first 'l' with 'L': ${str.replaceFirst("l", "L")}")
}
}字符串分割和连接
scala
object StringSplitJoin {
def main(args: Array[String]): Unit = {
val csv = "apple,banana,orange,grape"
val sentence = "The quick brown fox jumps over the lazy dog"
// 分割字符串
val fruits = csv.split(",")
val words = sentence.split(" ")
println("Fruits:")
fruits.foreach(println)
println("\nWords:")
words.foreach(println)
// 连接字符串
val joined1 = fruits.mkString(" | ")
val joined2 = words.mkString("[", ", ", "]")
println(s"\nJoined fruits: $joined1")
println(s"Joined words: $joined2")
// 使用分隔符
val numbers = Array(1, 2, 3, 4, 5)
val numberString = numbers.mkString(", ")
println(s"Numbers: $numberString")
// 字符串构建器
val sb = new StringBuilder()
sb.append("Hello")
sb.append(", ")
sb.append("World")
sb.append("!")
println(s"StringBuilder result: ${sb.toString}")
}
}字符串匹配和正则表达式
scala
import scala.util.matching.Regex
object StringMatching {
def main(args: Array[String]): Unit = {
val text = "My phone number is 123-456-7890 and email is user@example.com"
// 正则表达式
val phonePattern: Regex = """\d{3}-\d{3}-\d{4}""".r
val emailPattern: Regex = """[\w._%+-]+@[\w.-]+\.[A-Za-z]{2,}""".r
// 查找匹配
val phoneMatch = phonePattern.findFirstIn(text)
val emailMatch = emailPattern.findFirstIn(text)
println(s"Phone: ${phoneMatch.getOrElse("Not found")}")
println(s"Email: ${emailMatch.getOrElse("Not found")}")
// 查找所有匹配
val numbers = """\d+""".r
val allNumbers = numbers.findAllIn("There are 123 apples and 456 oranges").toList
println(s"All numbers: $allNumbers")
// 替换匹配
val censored = phonePattern.replaceAllIn(text, "XXX-XXX-XXXX")
println(s"Censored: $censored")
// 模式匹配
val input = "user@domain.com"
input match {
case emailPattern() => println("Valid email format")
case _ => println("Invalid email format")
}
// 提取组
val namePattern = """(\w+)\s+(\w+)""".r
val fullName = "John Doe"
fullName match {
case namePattern(first, last) =>
println(s"First name: $first, Last name: $last")
case _ =>
println("Name pattern not matched")
}
}
}字符串高级操作
字符串转换
scala
object StringConversion {
def main(args: Array[String]): Unit = {
// 字符串转数字
val numberStr = "123"
val floatStr = "3.14"
val boolStr = "true"
val intValue = numberStr.toInt
val floatValue = floatStr.toFloat
val boolValue = boolStr.toBoolean
println(s"String to Int: $intValue")
println(s"String to Float: $floatValue")
println(s"String to Boolean: $boolValue")
// 安全转换
def safeToInt(str: String): Option[Int] = {
try {
Some(str.toInt)
} catch {
case _: NumberFormatException => None
}
}
println(s"Safe conversion '123': ${safeToInt("123")}")
println(s"Safe conversion 'abc': ${safeToInt("abc")}")
// 字符串转集合
val str = "Hello"
val charList = str.toList
val charArray = str.toCharArray
println(s"String to List: $charList")
println(s"String to Array: ${charArray.mkString("[", ", ", "]")}")
// 数字转字符串
val num = 42
val numStr1 = num.toString
val numStr2 = String.valueOf(num)
println(s"Number to String: $numStr1")
println(s"Using valueOf: $numStr2")
}
}字符串格式化
scala
object StringFormatting {
def main(args: Array[String]): Unit = {
val name = "Alice"
val age = 30
val salary = 50000.0
// 使用 format 方法
val formatted1 = "Name: %s, Age: %d, Salary: %.2f".format(name, age, salary)
println(formatted1)
// 使用位置参数
val formatted2 = "Hello %1$s, you are %2$d years old. Nice to meet you, %1$s!".format(name, age)
println(formatted2)
// 数字格式化
val pi = 3.14159265359
println(f"Pi: $pi%8.3f") // 宽度8,3位小数
println(f"Pi: $pi%08.3f") // 用0填充
println(f"Pi: $pi%-8.3f") // 左对齐
// 百分比格式化
val percentage = 0.75
println(f"Success rate: $percentage%.1%%")
// 科学计数法
val bigNumber = 1234567.89
println(f"Big number: $bigNumber%.2e")
// 十六进制
val number = 255
println(f"Hex: $number%x")
println(f"Hex (uppercase): $number%X")
}
}字符串性能优化
scala
object StringPerformance {
def main(args: Array[String]): Unit = {
// 字符串连接性能比较
def concatenateWithPlus(n: Int): String = {
var result = ""
for (i <- 1 to n) {
result += s"Item $i "
}
result
}
def concatenateWithBuilder(n: Int): String = {
val sb = new StringBuilder()
for (i <- 1 to n) {
sb.append(s"Item $i ")
}
sb.toString
}
def concatenateWithMkString(n: Int): String = {
(1 to n).map(i => s"Item $i").mkString(" ")
}
// 性能测试
val n = 1000
val start1 = System.currentTimeMillis()
val result1 = concatenateWithPlus(n)
val time1 = System.currentTimeMillis() - start1
val start2 = System.currentTimeMillis()
val result2 = concatenateWithBuilder(n)
val time2 = System.currentTimeMillis() - start2
val start3 = System.currentTimeMillis()
val result3 = concatenateWithMkString(n)
val time3 = System.currentTimeMillis() - start3
println(s"String concatenation with +: ${time1}ms")
println(s"StringBuilder: ${time2}ms")
println(s"mkString: ${time3}ms")
// 字符串池
val str1 = "Hello"
val str2 = "Hello"
val str3 = new String("Hello")
println(s"str1 eq str2: ${str1 eq str2}") // true (字符串池)
println(s"str1 eq str3: ${str1 eq str3}") // false (新对象)
println(s"str1 == str3: ${str1 == str3}") // true (内容相同)
}
}实际应用示例
文本处理工具
scala
object TextProcessor {
def wordCount(text: String): Map[String, Int] = {
text.toLowerCase
.replaceAll("[^a-zA-Z\\s]", "") // 移除标点符号
.split("\\s+") // 按空白分割
.filter(_.nonEmpty) // 过滤空字符串
.groupBy(identity) // 按单词分组
.view.mapValues(_.length).toMap // 计算每个单词的出现次数
}
def reverseWords(text: String): String = {
text.split(" ").map(_.reverse).mkString(" ")
}
def isPalindrome(text: String): Boolean = {
val cleaned = text.toLowerCase.replaceAll("[^a-zA-Z0-9]", "")
cleaned == cleaned.reverse
}
def capitalizeWords(text: String): String = {
text.split(" ").map(word =>
if (word.nonEmpty) word.head.toUpper + word.tail.toLowerCase
else word
).mkString(" ")
}
def main(args: Array[String]): Unit = {
val text = "Hello world! This is a sample text for testing. Hello appears twice."
println("原文:")
println(text)
println("\n单词计数:")
wordCount(text).foreach { case (word, count) =>
println(s"$word: $count")
}
println(s"\n反转单词: ${reverseWords(text)}")
val palindromes = List("A man a plan a canal Panama", "race a car", "hello")
println("\n回文检测:")
palindromes.foreach { str =>
println(s"'$str' is palindrome: ${isPalindrome(str)}")
}
println(s"\n首字母大写: ${capitalizeWords("hello world from scala")}")
}
}模板引擎
scala
object SimpleTemplateEngine {
def render(template: String, variables: Map[String, String]): String = {
variables.foldLeft(template) { case (result, (key, value)) =>
result.replace(s"{{$key}}", value)
}
}
def renderWithDefaults(template: String, variables: Map[String, String], defaults: Map[String, String] = Map.empty): String = {
val allVars = defaults ++ variables
val variablePattern = """\{\{(\w+)\}\}""".r
variablePattern.replaceAllIn(template, m => {
val varName = m.group(1)
allVars.getOrElse(varName, s"{{$varName}}") // 保留未找到的变量
})
}
def main(args: Array[String]): Unit = {
val template = "Hello {{name}}, welcome to {{site}}! Your role is {{role}}."
val variables = Map(
"name" -> "Alice",
"site" -> "Scala Tutorial"
)
val defaults = Map(
"role" -> "student"
)
val result1 = render(template, variables ++ defaults)
val result2 = renderWithDefaults(template, variables, defaults)
println("简单渲染:")
println(result1)
println("\n带默认值的渲染:")
println(result2)
// 缺少变量的情况
val incompleteVars = Map("name" -> "Bob")
val result3 = renderWithDefaults(template, incompleteVars, defaults)
println("\n缺少变量的渲染:")
println(result3)
}
}配置文件解析器
scala
object ConfigParser {
case class Config(properties: Map[String, String]) {
def getString(key: String): Option[String] = properties.get(key)
def getInt(key: String): Option[Int] = properties.get(key).flatMap(v =>
try Some(v.toInt) catch { case _: NumberFormatException => None }
)
def getBoolean(key: String): Option[Boolean] = properties.get(key).map(_.toLowerCase == "true")
}
def parseConfig(configText: String): Config = {
val properties = configText
.split("\n")
.map(_.trim)
.filter(line => line.nonEmpty && !line.startsWith("#")) // 过滤空行和注释
.flatMap { line =>
line.split("=", 2) match {
case Array(key, value) => Some(key.trim -> value.trim)
case _ => None
}
}
.toMap
Config(properties)
}
def main(args: Array[String]): Unit = {
val configText =
"""# Database configuration
|host=localhost
|port=5432
|database=myapp
|username=admin
|password=secret123
|ssl_enabled=true
|connection_timeout=30
|
|# Application settings
|debug_mode=false
|max_users=1000""".stripMargin
val config = parseConfig(configText)
println("配置解析结果:")
println(s"Host: ${config.getString("host").getOrElse("unknown")}")
println(s"Port: ${config.getInt("port").getOrElse(0)}")
println(s"SSL Enabled: ${config.getBoolean("ssl_enabled").getOrElse(false)}")
println(s"Max Users: ${config.getInt("max_users").getOrElse(100)}")
println(s"Debug Mode: ${config.getBoolean("debug_mode").getOrElse(false)}")
}
}最佳实践
- 使用字符串插值:优先使用
s"$variable"而不是字符串连接 - 选择合适的插值器:
s用于一般插值,f用于格式化,raw用于原始字符串 - 性能考虑:大量字符串操作时使用
StringBuilder或函数式方法 - 避免空指针:使用
Option处理可能为空的字符串 - 正则表达式:复杂的字符串匹配使用正则表达式
- 不可变性:字符串是不可变的,操作会创建新字符串
掌握字符串操作是 Scala 编程的基础技能,这些技巧在实际开发中会经常用到。