Advertisement
Guest User

Untitled

a guest
Oct 12th, 2016
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.74 KB | None | 0 0
  1. import scala.util.parsing.combinator.RegexParsers
  2.  
  3. case class UrlTokens(
  4. scheme : Option[String],
  5. authorization : Option[(String, Option[String])],
  6. domains : List[String],
  7. port : Option[Int],
  8. path : Option[List[String]],
  9. query : Option[List[(String, Option[String])]],
  10. fragment : Option[List[(String, Option[String])]]
  11. )
  12.  
  13. /**
  14. * <p>
  15. * From Wikipedia:
  16. * <pre>
  17. * scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]
  18. * </pre>
  19. * </p>
  20. *
  21. * <p>
  22. * Parsing an URL:
  23. * </p>
  24. * <ol>
  25. * <li>Divide full URL at optional "://" to get scheme and "domain and" (the rest)</li>
  26. * <li>Divide "domain and" at optional "/" and optional "?" and optional "#" to get domain and/or path and/or query and/or fragment</li>
  27. * <li>Divide domain to optional authorization, domains and optional port</li>
  28. * <li>Divide path by "/"</li>
  29. * <li>Divide query and fragment by "&" and divide each pair at "=" to get key and optional value</li>
  30. * <ol>
  31. *
  32. */
  33. class UrlParser extends RegexParsers {
  34.  
  35. def expression = all ^^ {
  36. case (scheme, ((authorization, domains, port), path, query, fragment)) =>
  37. new UrlTokens(scheme, authorization, domains, port, path, query, fragment)
  38. }
  39.  
  40. val notSlash = """[^\/]+""".r
  41. val notDot = """[^\.]+""".r
  42. val notColon = """[^:]+""".r
  43. val notDotOrColonOrSlashOrQuestionmarkOrHash = """[^:\.\/\?\#]+""".r
  44. val notAt = """[^@]+""".r
  45. val notSlashOrQuestionmark = """[^\/\?]+""".r
  46. val numbers = """\d+""".r
  47. val encoded = """[^\=\&\/\#]+""".r
  48.  
  49. def all = opt(notColon <~ "://") ~ domainAnd ^^ { case optionalScheme ~ domainAnd => (optionalScheme, domainAnd) }
  50.  
  51. def domainAnd = domain ~ opt("/" ~> path) ~ opt("?" ~> valuePairs) ~ opt("#" ~> valuePairs) ^^ { case domain ~ optionalPath ~ optionalQuery ~ optionalFragment => (domain, optionalPath, optionalQuery, optionalFragment) }
  52.  
  53. def domain = opt(authorization <~ "@") ~ domains ~ opt(":" ~> port) ^^ { case optionalAuthorization ~ domains ~ optionalPort => (optionalAuthorization, domains, optionalPort) }
  54.  
  55. def authorization = notColon ~ opt(":" ~> notAt) ^^ { case user ~ optionalPassword => (user, optionalPassword) }
  56. def domains = repsep(notDotOrColonOrSlashOrQuestionmarkOrHash, ".")
  57. def port = numbers ^^ { case number => number.toInt }
  58.  
  59. def path = repsep(notSlashOrQuestionmark | "", "/")
  60. def valuePairs = repsep(pair, "&")
  61. def pair = encoded ~ "=" ~ opt(encoded) ^^ { case key ~ equal ~ optionalValue => (key, optionalValue) }
  62.  
  63. def apply(url : String) = {
  64. parseAll(expression, url) match {
  65. case Success(result, _) => Right(result)
  66. case Failure(error, _) => Left(error)
  67. case Error(error, _) => Left(error)
  68. }
  69. }
  70. }
  71.  
  72. object UrlParser {
  73. lazy val urlParser = new UrlParser
  74.  
  75. def apply(url : String) = urlParser(url)
  76. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement