我需要为学校的 scala3 中的 find 命令编写一个 CLI。语法是:
run [path] [--filterName filterParameter]
。我目前让它一次对一个过滤器起作用,但是一旦它尝试使用两个或多个过滤器的命令,只有最后一个生效。
例如,如果我运行:
run src/ --name main
,我会得到输出src/main
和src/main/scala/find/cli/main.scala
,这是正确的。
如果我运行:
run src/ --type scala
我会正确获取所有 scala 文件。
但是如果我运行:
run src/ --name main --type scala
,而不是得到src/main/scala/find/cli/main.scala
,我会得到与运行run src/ --type scala
相同的输出。如果我反转过滤器,那么运行:run src/ --type scala --name main
我得到与运行相同的输出:run src/ --name main
。
cli.scala:
package find
package cli
import scala.collection.mutable
import scala.util.matching.Regex
val usageMap: mutable.LinkedHashMap[String, String] = mutable.LinkedHashMap(
"name" -> "[--name X] (where X is a string)",
"type" -> "[--type X] (where X is a string)",
)
var path = ""
var file: cs214.Entry = cs214.MockFile("zef", None, 2)
var failMsg = ""
/** Command-line interface for the `find` program.
*
* Note: this function is provided to you and you do not need to understand how
* it works yet.
*
* @param args
* the command-line arguments.
*/
@main def cs214find(args: String*) = entryPoint(args)(cs214.open)
def entryPoint(args: Seq[String])(open: String => cs214.Entry): Boolean =
if args.length < 1 then
return fail("No path argument given.")
path = args.head
path match
case "--help" => false
case _ =>
file =
try
open(path)
catch
case _: java.nio.file.NoSuchFileException =>
return fail(createFailMsg(error = f"Path '$path' does not exist."))
case e: Exception =>
return fail(createFailMsg(error = f"Open raised an exception: ${e.getMessage}."))
var results: List[List[String]] = List()
var filters = args.mkString(" ").split("--")
filters(0) = filters(0).replaceAll(path + " ", "")
for filter <- filters yield
getFilterCondition(filter) match
case Nil => None
case l => results = l :: results
if failMsg.nonEmpty then fail(failMsg)
else if results.length == 1 then
showResults(results.head)
true
else
results.foreach(showResults)
true
def showResults(res: List[String]) =
for f <- res yield println(f)
def getFilterCondition(filter: String): List[String] =
filter match
case s"name $name" => find(file, (entry: cs214.Entry) => (entry.isDirectory() && entry.name() == name) || (!entry.isDirectory() && entry.name().split("\\.").head == name))
case s"type $extension" => find(file, (entry: cs214.Entry) => !entry.isDirectory() && entry.name().split("\\.")(1) == `extension`)
case filter => List()
def createFailMsg(error: String = "", filter: String = ""): String =
f"Error: $error\nUsage: ${usageMap(filter)}"
def fail(msg: String): Boolean =
System.err.println(msg)
false
find.scala:
package find
def find(entry: cs214.Entry, f: cs214.Entry => Boolean): List[String] =
var res: List[String] = List()
if f(entry) then res = List(entry.path())
if entry.isDirectory() && entry.hasChildren() then res = find(entry.firstChild(), f) ::: res
if entry.hasNextSibling() then res = find(entry.nextSibling(), f) ::: res
res.reverse
结果似乎在 cli.scala 中丢失了:
for filter <- filters yield
getFilterCondition(filter) match <-- results lost
case Nil => None
case l => results = l :: results
我不明白如何以及为什么。
任何帮助将不胜感激。
P.S: 有些部分没有完成,比如非过滤器和深度搜索的实现,这是正常的。
这对我来说是一个愚蠢的错误,但我需要像这样调用 getFilterCondition:
getFilterCondition(filter.trim())
而不是 getFilterCondition(filter)
。