This method is somewhat cycle-intensive, as we have to constantly reshuffle the string around -- even if we want to just access it. So it's no speed demon. However, I can see of no other method to do this. If you need to randomly-access data and not just dump it into a big linear string, this method works.
I don't include an example of whole-row deletion or insertion, but that's an exercise best left up to the reader. (Besides, it's simple.

Curious if anyone else has hit upon a more memory/cycle conversative method, but honestly I just don't see how it could be done in any way but this. If llSubStringIndex let us start searching from any arbitary positon, instead of just at the beginning, one could avoid having to cut/paste the examined data back into the string.
Anyway, if you have need of such a thing (storing large data but can't use lists due to space issues), then here's a way of doing it.
Here's an example:
CODE
// List-like strings, by Fenrir Reitveld (01/03/06)
//
default
{
state_entry()
{
string liststring ;
string testitem1 = "This is a test." ;
string testitem2 = "12345" ;
string testitem3 = (string)NULL_KEY ;
integer listcount = 4 ;
integer i ;
// Build a short test database
for (i = 0; i < listcount; i++)
liststring += "Item " + (string)(i + 1) + "," + testitem1 + "," + testitem2 + "," + testitem3 + "&" ;
// Okay, let's replace item 2
for (i = 0; i < listcount; i++)
{
// first, find the first & in liststring and return it -- that's our data
string parsed = llGetSubString (liststring, 0, llSubStringIndex (liststring, "&") - 1) ;
// Now, delete what we returned from the liststring
liststring = llDeleteSubString (liststring, 0, llSubStringIndex (liststring, "&"));
// Now, convert what was returned into a list
list iteml = llCSV2List (parsed) ;
// Manipulate this list as if it were normal
if (llList2String (iteml, 0) == "Item 2")
{
iteml = llDeleteSubList (iteml, 0, 0) ;
iteml = llListInsertList (iteml, ["Replaced!"], 0) ;
// Now we're re-inserting the modified version back into the liststring
liststring += llList2CSV(iteml) + "&" ;
} else
// Otherwise, with no modification, we just put it back in the liststring
liststring += parsed + "&" ;
}
// Okay, let's just dump out what we've got...
for (i = 0; i < listcount; i++)
{
// first, find the first & in liststring and return it -- that's our data
string parsed = llGetSubString (liststring, 0, llSubStringIndex (liststring, "&") - 1) ;
// Now, delete what we returned from the liststring
liststring = llDeleteSubString (liststring, 0, llSubStringIndex (liststring, "&"));
// Now, convert what was returned into a list
list iteml = llCSV2List (parsed) ;
// Manipulate this list as if it were normal
llWhisper (0, (string) (i + 1) + ". " + llList2String (iteml, 0) + " " + llList2String (iteml, 1) + " " + llList2String (iteml, 2) + " " + llList2String (iteml, 3)) ;
// No modification, so we just put it back in the liststring
liststring += parsed + "&" ;
}
}
}