Scala:遍历字符串的每个字符并使用模式匹配

Scala: iterate through every character of a String and use pattern matching

我想我想做的事情很明显。对于 string1 中的每个字符,使用模式匹配打印一些内容。 (我在那里有 string2,因为我将使用 string1 的模式匹配对字符串 2 和 return 字符串 2 做一些事情)

出于某种原因,我的代码只打印出“()”。

另外,我如何确保我的代码 return 是一个字符串。当我把代码放在终端时,它说: (string1: String)String => Unit ,我怎么让它说 (string1: String)String => String

def stringPipeline(string1: String) = (string2: String) => {

  for(c <- string1) {
    c match {
      case 'u' => "Upper Case"
      case 'r' => "reverse"
      case _ => "do something"
    }
  }
}

编辑:

我只想指出我想用 string2 做什么:

def stringPipeline(string1: String) = (string2: String) => { 
    for(c <- string1) yield { 
        c match { 
            case 'U' => string2.toUpperCase 
            case 'r' => string2.reverse } } } 

但它是 return 一个 vector/list 字符串。我希望所有这些情况都适用于同一个 string2 对象。因此,如果我在 "hello" 上测试该方法,它应该 return "OLLEH".

谢谢

你忘记了 for ( ... ) 之后的 yield,因此最后一个 for 简单地运行,扔掉体内的所有东西,最后 return 是一个单元 ().

如果你想return一些东西,你应该使用这样的东西:

def stringPipeline(string1: String) = (string2: String) => {
  for (c <- string1) yield {
    c match {
      case 'u' => "Upper Case"
      case 'r' => "reverse"
      case _ => "do something"
    }
  }
}

这将为每个 string2 提供某种 "list of action descriptions"。

如果你真的想print立即做某事,你可以这样做:

def stringPipeline(string1: String) = (string2: String) => {
  for (c <- string1) {
    println(c match {
      case 'u' => "Upper Case"
      case 'r' => "reverse"
      case _ => "do something"
    })
  }
}

但现在这样,return既没有任何意义,也没有任何副作用。

编辑:

更新:如果您想将 string1 视为一系列操作,将 string2 视为您要应用这些操作的 "material",您可以这样做:

def stringPipeline(string1: String) = (string2: String) => {
  string1.foldLeft(string2) { 
    case (s, 'u') => s.toUpperCase
    case (s, 'r') => s.reverse
    case (_, x) => 
      throw new Error("undefined string manipulation: " + x)
  }
}

以上代码执行以下操作:它从 string2 开始,然后将 string1 中的每个操作应用于迄今为止累积的所有转换的结果。

如果您的目标是接收一个对字符串执行模式的函数,您可以这样做:

def stringPipeline(pattern : String) = {
  def handleString(s : String, restPattern : List[Char]) : String = {
     restPattern match{
      case hd :: tl => {
        hd match{
          case 'u' => handleString(s.toUpperCase(), tl)
          case 'r' => handleString(s.reverse, tl)
          case _ => handleString(s, tl)
        }
      }
      case Nil => s    
    }
  }    
  s : String => handleString(s, pattern.toList)
}

这个函数returns一个递归函数,一个接一个地执行模式的一个字母,最后returns结果字符串。

然后你可以做类似的事情:

val s = "urx"
val fun = stringPipeline(s)
println(fun("hello"))

哪个returnsOLLEH

但是,它不是一种迭代方法,而是一种递归方法(更适合像 Scala 这样的函数式编程语言)。

如果您将定义粘贴到 Scala REPL 中,您将看到您定义的函数类型是

stringPipeline: (string1: String)String => Unit

即一个函数,它以字符串 string1 作为输入,return 是一个以第二个字符串 string2 作为输入的闭包,并且 returning Unit,就像 void在 Java 中并且只有值 ().

那么为什么 returned 闭包有 Unit 作为 return 类型?它的正文只包含一个表达式:

for(c <- string1) {
    c match {
      case 'u' => "Upper Case"
      case 'r' => "reverse"
      case _ => "do something"
    }
}

for 计算其内部表达式

c match {
    case 'u' => "Upper Case"
    case 'r' => "reverse"
    case _ => "do something"
}

对于 string1 中的每个可能的 c,然后 returns ()。换句话说,for 不让内部产生的值通过。

如果你想打印字符串"Upper Case"你需要写

    case 'u' => println("Upper Case")

那么闭包的 return 值仍将是 (),但它的计算将打印 match 表达式中的字符串作为副作用。

附带说明一下,如果不使用参数 string2 为什么要引入它?

编辑

由于循环内函数的输出用作循环的下一个循环的输入,因此您需要一个折叠函数,即像这样的东西:

def stringPipeline(string1: String) = (string2: String) => {
    string1.foldLeft(string2)((s: String, c: Char) =>
        c match {
            case 'u' => s.toUpperCase
            case 'r' => s.reverse
            case _   => s
        }
    )
}

您需要实现管道,使其折叠 ops 字符串的字符,每个字符都是管道中的一个转换阶段。

您从 input 字符串开始第一次折叠,然后 ops 字符串的每个后续折叠将转换最后一次折叠的输出。

现在,折叠ops字符串时,只需要在遇到不同的字符时添加不同的变换操作即可。

def stringPipeline(ops: String) = (input: String) => {
  ops.toLowerCase.foldLeft(input)((str: String, op: Char) => op match {
    case 'u' =>
      println("Operator - 'u' :: Transforming - Upper Case")
      str.toUpperCase
    case 'r' =>
      println("Operator - 'r' :: Transforming - Reverse")
      str.reverse
    case _ =>
      println("Operator - 'unknown' :: Doing Nothing")
      str
  })
}

val pipeline1 = stringPipeline("ur")

val s1 = "abcde"

val s1p1 = pipeline1(s1)

// Operator - 'u' :: Transforming - Upper Case
// Operator - 'r' :: Transforming - Reverse
// s1p1: String = EDCBA