Skip to content

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)}")
  }
}

最佳实践

  1. 使用字符串插值:优先使用 s"$variable" 而不是字符串连接
  2. 选择合适的插值器s 用于一般插值,f 用于格式化,raw 用于原始字符串
  3. 性能考虑:大量字符串操作时使用 StringBuilder 或函数式方法
  4. 避免空指针:使用 Option 处理可能为空的字符串
  5. 正则表达式:复杂的字符串匹配使用正则表达式
  6. 不可变性:字符串是不可变的,操作会创建新字符串

掌握字符串操作是 Scala 编程的基础技能,这些技巧在实际开发中会经常用到。

本站内容仅供学习和研究使用。