Url Parsing in Scheme

Here’s the translation of the Go URL parsing example to Scheme, formatted in Markdown suitable for Hugo:

Our URL parsing program demonstrates how to parse URLs in Scheme. URLs provide a uniform way to locate resources.

(import (scheme base)
        (scheme write)
        (srfi 13) ; For string operations
        (srfi 115)) ; For regular expressions

(define (parse-url url-string)
  (let* ((url-parts (string-split url-string "#"))
         (main-url (car url-parts))
         (fragment (if (> (length url-parts) 1) (cadr url-parts) #f))
         (scheme-parts (string-split main-url "://"))
         (scheme (car scheme-parts))
         (rest (cadr scheme-parts))
         (auth-host-path (string-split rest "/"))
         (auth-host (car auth-host-path))
         (path (if (> (length auth-host-path) 1) 
                   (string-join (cdr auth-host-path) "/")
                   ""))
         (auth-host-parts (string-split auth-host "@"))
         (user-pass (if (> (length auth-host-parts) 1) 
                        (car auth-host-parts) 
                        #f))
         (host-port (if user-pass 
                        (cadr auth-host-parts) 
                        (car auth-host-parts)))
         (host-port-parts (string-split host-port ":"))
         (host (car host-port-parts))
         (port (if (> (length host-port-parts) 1) 
                   (cadr host-port-parts) 
                   #f))
         (query-parts (string-split path "?"))
         (path-without-query (car query-parts))
         (query (if (> (length query-parts) 1) 
                    (cadr query-parts) 
                    #f)))
    (list scheme user-pass host port path-without-query query fragment)))

(define (parse-query query-string)
  (if query-string
      (map (lambda (param)
             (let ((kv (string-split param "=")))
               (cons (car kv) (cadr kv))))
           (string-split query-string "&"))
      '()))

(define (main)
  (let* ((s "postgres://user:pass@host.com:5432/path?k=v#f")
         (parsed-url (parse-url s))
         (scheme (list-ref parsed-url 0))
         (user-pass (list-ref parsed-url 1))
         (host (list-ref parsed-url 2))
         (port (list-ref parsed-url 3))
         (path (list-ref parsed-url 4))
         (query (list-ref parsed-url 5))
         (fragment (list-ref parsed-url 6)))
    
    (display "Scheme: ") (display scheme) (newline)
    (display "User:Pass: ") (display user-pass) (newline)
    (when user-pass
      (let ((user-pass-parts (string-split user-pass ":")))
        (display "Username: ") (display (car user-pass-parts)) (newline)
        (display "Password: ") (display (cadr user-pass-parts)) (newline)))
    (display "Host:Port: ") (display host) (display ":") (display port) (newline)
    (display "Host: ") (display host) (newline)
    (display "Port: ") (display port) (newline)
    (display "Path: ") (display path) (newline)
    (display "Fragment: ") (display fragment) (newline)
    (display "Query: ") (display query) (newline)
    (let ((parsed-query (parse-query query)))
      (display "Parsed Query: ") (display parsed-query) (newline)
      (when (not (null? parsed-query))
        (display "Value of 'k': ") (display (cdr (assoc "k" parsed-query))) (newline)))))

(main)

This Scheme program parses a URL and extracts its components. Here’s a breakdown of what it does:

  1. We define a parse-url function that takes a URL string and breaks it down into its components: scheme, user:pass, host, port, path, query, and fragment.

  2. We also define a parse-query function to parse the query string into a list of key-value pairs.

  3. In the main function, we:

    • Parse an example URL
    • Print out each component of the URL
    • Parse and print the query parameters
  4. The program uses string manipulation functions from SRFI 13 to split strings and extract parts of the URL.

Running this program would produce output similar to:

Scheme: postgres
User:Pass: user:pass
Username: user
Password: pass
Host:Port: host.com:5432
Host: host.com
Port: 5432
Path: /path
Fragment: f
Query: k=v
Parsed Query: ((k . v))
Value of 'k': v

This example demonstrates URL parsing in Scheme, showing how to extract and manipulate different parts of a URL.