patch 8.2.3818: cannot filter or map characters in a string

Problem:    Cannot filter or map characters in a string.
Solution:   Make filter() and map() work on a string. (Naruhiko Nishino,
            closes #9327)
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 004f9d4..21cf3f6 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2628,7 +2628,8 @@
 feedkeys({string} [, {mode}])	Number	add key sequence to typeahead buffer
 filereadable({file})		Number	|TRUE| if {file} is a readable file
 filewritable({file})		Number	|TRUE| if {file} is a writable file
-filter({expr1}, {expr2})	List/Dict  remove items from {expr1} where
+filter({expr1}, {expr2})	List/Dict/Blob/String
+					remove items from {expr1} where
 					{expr2} is 0
 finddir({name} [, {path} [, {count}]])
 				String	find directory {name} in {path}
@@ -2786,14 +2787,16 @@
 log({expr})			Float	natural logarithm (base e) of {expr}
 log10({expr})			Float	logarithm of Float {expr} to base 10
 luaeval({expr} [, {expr}])	any	evaluate |Lua| expression
-map({expr1}, {expr2})		List/Dict  change each item in {expr1} to {expr}
+map({expr1}, {expr2})		List/Dict/Blob/String
+					change each item in {expr1} to {expr2}
 maparg({name} [, {mode} [, {abbr} [, {dict}]]])
 				String or Dict
 					rhs of mapping {name} in mode {mode}
 mapcheck({name} [, {mode} [, {abbr}]])
 				String	check for mappings matching {name}
-mapnew({expr1}, {expr2})	List/Dict  like |map()| but creates a new List
-					   or Dictionary
+mapnew({expr1}, {expr2})	List/Dict/Blob/String
+					like |map()| but creates a new List or
+					Dictionary
 mapset({mode}, {abbr}, {dict})	none	restore mapping from |maparg()| result
 match({expr}, {pat} [, {start} [, {count}]])
 				Number	position where {pat} matches in {expr}
@@ -4878,10 +4881,11 @@
 
 
 filter({expr1}, {expr2})				*filter()*
-		{expr1} must be a |List|, |Blob| or |Dictionary|.
+		{expr1} must be a |List|, |String|, |Blob| or |Dictionary|.
 		For each item in {expr1} evaluate {expr2} and when the result
-		is zero remove the item from the |List| or |Dictionary|. For a
-		|Blob| each byte is removed.
+		is zero or false remove the item from the |List| or
+		|Dictionary|.  Similarly for each byte in a |Blob| and each
+		charactor in a |String|.
 
 		{expr2} must be a |string| or |Funcref|.
 
@@ -4916,14 +4920,16 @@
 <		If you do not use "val" you can leave it out: >
 			call filter(myList, {idx -> idx % 2 == 1})
 <
-		The operation is done in-place.  If you want a |List| or
-		|Dictionary| to remain unmodified make a copy first: >
+		For a |List| and a |Dictionary| the operation is done
+		in-place.  If you want it to remain unmodified make a copy
+		first: >
 			:let l = filter(copy(mylist), 'v:val =~ "KEEP"')
 
-<		Returns {expr1}, the |List| , |Blob| or |Dictionary| that was
-		filtered.  When an error is encountered while evaluating
-		{expr2} no further items in {expr1} are processed.  When
-		{expr2} is a Funcref errors inside a function are ignored,
+<		Returns {expr1}, the |List| or |Dictionary| that was filtered,
+		or a new |Blob| or |String|. 
+		When an error is encountered while evaluating {expr2} no
+		further items in {expr1} are processed.
+		When {expr2} is a Funcref errors inside a function are ignored,
 		unless it was defined with the "abort" flag.
 
 		Can also be used as a |method|: >
@@ -7566,16 +7572,19 @@
 <		{only available when compiled with the |+lua| feature}
 
 map({expr1}, {expr2})					*map()*
-		{expr1} must be a |List|, |Blob| or |Dictionary|.
-		Replace each item in {expr1} with the result of evaluating
-		{expr2}.  For a |Blob| each byte is replaced.
+		{expr1} must be a |List|, |String|, |Blob| or |Dictionary|.
+		When {expr1} is a |List|| or |Dictionary|, replace each
+		item in {expr1} with the result of evaluating {expr2}.
+		For a |Blob| each byte is replaced.
+		For a |String|, each character, including composing
+		characters, is replaced.
 		If the item type changes you may want to use |mapnew()| to
 		create a new List or Dictionary.  This is required when using
 		Vim9 script.
 
-		{expr2} must be a |string| or |Funcref|.
+		{expr2} must be a |String| or |Funcref|.
 
-		If {expr2} is a |string|, inside {expr2} |v:val| has the value
+		If {expr2} is a |String|, inside {expr2} |v:val| has the value
 		of the current item.  For a |Dictionary| |v:key| has the key
 		of the current item and for a |List| |v:key| has the index of
 		the current item.  For a |Blob| |v:key| has the index of the
@@ -7605,14 +7614,15 @@
 <		If you do not use "key" you can use a short name: >
 			call map(myDict, {_, val -> 'item: ' . val})
 <
-		The operation is done in-place.  If you want a |List| or
-		|Dictionary| to remain unmodified make a copy first: >
+		The operation is done in-place for a |List| and |Dictionary|.
+		If you want it to remain unmodified make a copy first: >
 			:let tlist = map(copy(mylist), ' v:val . "\t"')
 
-<		Returns {expr1}, the |List|, |Blob| or |Dictionary| that was
-		filtered.  When an error is encountered while evaluating
-		{expr2} no further items in {expr1} are processed.  When
-		{expr2} is a Funcref errors inside a function are ignored,
+<		Returns {expr1}, the |List| or |Dictionary| that was filtered,
+		or a new |Blob| or |String|.
+		When an error is encountered while evaluating {expr2} no
+		further items in {expr1} are processed.
+		When {expr2} is a Funcref errors inside a function are ignored,
 		unless it was defined with the "abort" flag.
 
 		Can also be used as a |method|: >