Task

Provide a function or mechanism to convert a provided string into URL encoding representation.

In URL encoding, special characters, control characters and extended characters
are converted into a percent symbol followed by a two digit hexadecimal code,
So a space character encodes into %20 within the string.

For the purposes of this task, every character except 0-9, A-Z and a-z requires conversion, so the following characters all require conversion by default:

 ASCII control codes (Character ranges 00-1F hex (0-31 decimal) and 7F (127 decimal).
 ASCII symbols (Character ranges 32-47 decimal (20-2F hex))
 ASCII symbols (Character ranges 58-64 decimal (3A-40 hex))
 ASCII symbols (Character ranges 91-96 decimal (5B-60 hex))
 ASCII symbols (Character ranges 123-126 decimal (7B-7E hex))
 Extended characters with character codes of 128 decimal (80 hex) and above.


Example

The string "http://foo bar/" would be encoded as "http%3A%2F%2Ffoo%20bar%2F".



Variations

 Lowercase escapes are legal, as in "http%3a%2f%2ffoo%20bar%2f".
 Some standards give different rules: RFC 3986, Uniform Resource Identifier (URI): Generic Syntax, section 2.3, says that "-._~" should not be encoded. HTML 5, section 4.10.22.5 URL-encoded form data, says to preserve "-._*", and to encode space " " to "+". The options below provide for utilization of an exception string, enabling preservation (non encoding) of particular characters to meet specific standards.


Options

It is permissible to use an exception string (containing a set of symbols
that do not need to be converted).
However, this is an optional feature and is not a requirement of this task.



Related tasks
 
   URL decoding
   URL parser


function urlencode
{
	typeset decoded=$1 encoded= rest= c=
	typeset rest2= bug='rest2=${rest}'
 
	if [[ -z ${BASH_VERSION} ]]; then
		# bug /usr/bin/sh HP-UX 11.00
		typeset _decoded='xyz%26xyz'
		rest="${_decoded#?}"
		c="${_decoded%%${rest}}"
		if (( ${#c} != 1 )); then
			typeset qm='????????????????????????????????????????????????????????????????????????'
			typeset bug='(( ${#rest} > 0 )) && typeset -L${#rest} rest2="${qm}" || rest2=${rest}'
		fi
	fi
 
	rest="${decoded#?}"
	eval ${bug}
	c="${decoded%%${rest2}}"
	decoded="${rest}"
 
	while [[ -n ${c} ]]; do
		case ${c} in
		[-a-zA-z0-9.])
			;;
		' ')
			c='+'
			;;
		*)
			c=$(printf "%%%02X" "'$c")
			;;
		esac
 
		encoded="${encoded}${c}"
 
		rest="${decoded#?}"
		eval ${bug}
		c="${decoded%%${rest2}}"
		decoded="${rest}"
	done
 
	if [[ -n ${BASH_VERSION:-} ]]; then
		\echo -E "${encoded}"
	else
		print -r -- "${encoded}"
	fi
}
 