import scala.
util.
{Left
=> Failed, Right
=> Ok
}
def |+|
(that
: UriException
): UriException
= new UriException
{ def explain
= self.
explain +
" | " + that.
explain }
}
def explain
= s
"can not translate '$code'" }
def explain
= s
"'$c' can't be appeared in URI" }
type Result
= Either
[UriException, String
]
def |+|
(that
: Result
): Result
= (self, that
) match { case (Ok
(s1
), Ok
(s2
)) => Ok
(s1 + s2
) case (Failed
(ex1
), Failed
(ex2
)) => Failed
(ex1 |+| ex2
) case (f
@Failed
(_),
_) => f
case (_, f
@Failed
(_)) => f
}
}
"20" -> " ",
"21" -> "!",
"24" -> "$",
"25" -> "%",
"28" -> "(",
"29" -> ")",
"2a" -> "*"
)
val scChar
= code2sc.
values map
(_.
head)
def toSecialCharacter
(c1
: Char, c2
: Char
): Result
= { val code
= (c1.
toString + c2.
toString).
toLowerCase
(code2sc get code
) match { case Some
(specialChar
) => Ok
(specialChar
) case None
=> Failed
(NotFound
("%" + code
)) }
}
def decode
(uri
: String
): Result
= { @annotation.tailrec
def loop
(chars
: List
[Char
], res
: Result
= Ok
("")): Result
= chars
match { case '%' :: a
:: b
:: rest
=> loop
(rest, res |+| toSecialCharacter
(a, b
)) if (scChar exists
(_ == c
)) loop
(rest, res |+| Failed
(Flaw
(c
))) else loop
(rest, res |+| Ok
(c.
toString)) }
loop(uri.toList)
}
def prettyFormat
(res
: Result
): String
= res
match { case Failed
(reason
) => s
"Failed ($reason)" case Ok
(decoded
) => decoded
}
val prettyPrint
= decode
_ andThen prettyFormat
_ andThen println
_
def main
(args
: Array
[String
]) { import scala.
util.
{Try, Success, Failure
} import java.
io.
{File, FileInputStream
=> FIS
}
@annotation.tailrec
def loop
(sc
: Scanner, remain
: Int
): Unit
= (sc.
hasNextLine, remain
) match { case (true,
_) => prettyPrint
(sc.
nextLine.
trim take
80); loop
(sc, remain -
1) }
List("""Happy%20Joy%20Joy%21""", """http://a...content-available-to-author-only...t.com/%2a""") foreach prettyPrint
}
}
b2JqZWN0IE1haW4gewoJaW1wb3J0IHNjYWxhLnV0aWwue0xlZnQgPT4gRmFpbGVkLCBSaWdodCA9PiBPa30KCQoJc2VhbGVkIHRyYWl0IFVyaUV4Y2VwdGlvbiB7IHNlbGYgPT4KCQlkZWYgZXhwbGFpbjogU3RyaW5nCQoJCQoJCWRlZiB8K3wodGhhdDogVXJpRXhjZXB0aW9uKTogVXJpRXhjZXB0aW9uID0gbmV3IFVyaUV4Y2VwdGlvbiB7CgkJCWRlZiBleHBsYWluID0gc2VsZi5leHBsYWluICsgIiB8ICIgKyB0aGF0LmV4cGxhaW4KCQl9CgoJCW92ZXJyaWRlIGRlZiB0b1N0cmluZyA9IGV4cGxhaW4KCX0KCgljYXNlIGNsYXNzIE5vdEZvdW5kKGNvZGU6IFN0cmluZykgZXh0ZW5kcyBVcmlFeGNlcHRpb24gewoJCWRlZiBleHBsYWluID0gcyJjYW4gbm90IHRyYW5zbGF0ZSAnJGNvZGUnIgoJfQoKCWNhc2UgY2xhc3MgRmxhdyhjOiBDaGFyKSBleHRlbmRzIFVyaUV4Y2VwdGlvbiB7CgkJZGVmIGV4cGxhaW4gPSBzIickYycgY2FuJ3QgYmUgYXBwZWFyZWQgaW4gVVJJIgoJfQoKCXR5cGUgUmVzdWx0ID0gRWl0aGVyW1VyaUV4Y2VwdGlvbiwgU3RyaW5nXQoJCglpbXBsaWNpdCBjbGFzcyBSZXN1bHRQbHVzKHNlbGY6IFJlc3VsdCkgewoJCWRlZiB8K3wodGhhdDogUmVzdWx0KTogUmVzdWx0ID0gKHNlbGYsIHRoYXQpIG1hdGNoIHsKCQkJY2FzZSAoT2soczEpLCBPayhzMikpICAgICAgICAgICA9PiBPayhzMSArIHMyKQoJCQljYXNlIChGYWlsZWQoZXgxKSwgRmFpbGVkKGV4MikpID0+IEZhaWxlZChleDEgfCt8IGV4MikKCQkJY2FzZSAoZkBGYWlsZWQoXyksIF8pICAgICAgICAgICA9PiBmCgkJCWNhc2UgKF8sIGZARmFpbGVkKF8pKSAgICAgICAgICAgPT4gZgoJCX0KCX0KCgl2YWwgY29kZTJzYyA9IE1hcCgKCQkiMjAiIC0+ICIgIiwgCgkJIjIxIiAtPiAiISIsIAoJCSIyNCIgLT4gIiQiLCAKCQkiMjUiIC0+ICIlIiwgCgkJIjI4IiAtPiAiKCIsIAoJCSIyOSIgLT4gIikiLCAKCQkiMmEiIC0+ICIqIgoJKQoJdmFsIHNjQ2hhciA9IGNvZGUyc2MudmFsdWVzIG1hcCAoXy5oZWFkKQoKCWRlZiB0b1NlY2lhbENoYXJhY3RlcihjMTogQ2hhciwgYzI6IENoYXIpOiBSZXN1bHQgPSB7CgkJdmFsIGNvZGUgPSAoYzEudG9TdHJpbmcgKyBjMi50b1N0cmluZykudG9Mb3dlckNhc2UKCgkJKGNvZGUyc2MgZ2V0IGNvZGUpIG1hdGNoIHsKCQkJY2FzZSBTb21lKHNwZWNpYWxDaGFyKSA9PiBPayhzcGVjaWFsQ2hhcikKCQkJY2FzZSBOb25lICAgID0+IEZhaWxlZChOb3RGb3VuZCgiJSIgKyBjb2RlKSkKCQl9Cgl9CgoJZGVmIGRlY29kZSh1cmk6IFN0cmluZyk6IFJlc3VsdCA9IHsKCQlAYW5ub3RhdGlvbi50YWlscmVjCgkJZGVmIGxvb3AoY2hhcnM6IExpc3RbQ2hhcl0sIHJlczogUmVzdWx0ID0gT2soIiIpKTogUmVzdWx0ID0gY2hhcnMgbWF0Y2ggewoJCQljYXNlICclJyA6OiBhIDo6IGIgOjogcmVzdCA9PiBsb29wKHJlc3QsIHJlcyB8K3wgdG9TZWNpYWxDaGFyYWN0ZXIoYSwgYikpCgkJCWNhc2UgYyAgIDo6IHJlc3QgICAgICAgICAgID0+IAoJCQkJaWYgKHNjQ2hhciBleGlzdHMgKF8gPT0gYykpIGxvb3AocmVzdCwgcmVzIHwrfCBGYWlsZWQoRmxhdyhjKSkpCgkJCQllbHNlIGxvb3AocmVzdCwgcmVzIHwrfCBPayhjLnRvU3RyaW5nKSkKCQkJY2FzZSBOaWwgICAgICAgICAgICAgICAgICAgPT4gcmVzCgkJfQoKCQlsb29wKHVyaS50b0xpc3QpCgl9CgkKCWRlZiBwcmV0dHlGb3JtYXQocmVzOiBSZXN1bHQpOiBTdHJpbmcgPSByZXMgbWF0Y2ggewoJCWNhc2UgRmFpbGVkKHJlYXNvbikgPT4gcyJGYWlsZWQgKCRyZWFzb24pIgoJCWNhc2UgT2soZGVjb2RlZCkgICAgPT4gZGVjb2RlZAoJfQoJCgl2YWwgcHJldHR5UHJpbnQgPSBkZWNvZGUgXyBhbmRUaGVuIHByZXR0eUZvcm1hdCBfIGFuZFRoZW4gcHJpbnRsbiBfCgoJZGVmIG1haW4oYXJnczogQXJyYXlbU3RyaW5nXSkgewoJCWltcG9ydCBzY2FsYS51dGlsLntUcnksIFN1Y2Nlc3MsIEZhaWx1cmV9CgkJaW1wb3J0IGphdmEudXRpbC5TY2FubmVyCgkJaW1wb3J0IGphdmEuaW8ue0ZpbGUsIEZpbGVJbnB1dFN0cmVhbSA9PiBGSVN9CgoJCUBhbm5vdGF0aW9uLnRhaWxyZWMKCQlkZWYgbG9vcChzYzogU2Nhbm5lciwgcmVtYWluOiBJbnQpOiBVbml0ID0gKHNjLmhhc05leHRMaW5lLCByZW1haW4pIG1hdGNoIHsKCQkJY2FzZSAoXywgMCkgICAgID0+ICgpCgkJCWNhc2UgKGZhbHNlLCBfKSA9PiAoKQoJCQljYXNlICh0cnVlLCBfKSAgPT4gcHJldHR5UHJpbnQoc2MubmV4dExpbmUudHJpbSB0YWtlIDgwKTsgbG9vcChzYywgcmVtYWluIC0gMSkKCQl9CgkJCgkJTGlzdCgiIiJIYXBweSUyMEpveSUyMEpveSUyMSIiIiwgIiIiaHR0cDovL2EuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLnQuY29tLyUyYSIiIikgZm9yZWFjaCBwcmV0dHlQcmludAoJfQp9