// indexedproperty.cs
using system;
public class document
{
// type allowing the document to be viewed like an array of words:
public class wordcollection
{
readonly document document; // the containing document
internal wordcollection(document d)
{
document = d;
}
// helper function -- search character array "text", starting at
// character "begin", for word number "wordcount." returns false
// if there are less than wordcount words. sets "start" and
// length" to the position and length of the word within text:
private bool getword(char[] text, int begin, int wordcount,
out int start, out int length)
{
int end = text.length;
int count = 0;
int inword = -1;
start = length = 0;
for (int i = begin; i <= end; ++i)
{
bool isletter = i < end && char.isletterordigit(text[i]);
if (inword >= 0)
{
if (!isletter)
{
if (count++ == wordcount)
{
start = inword;
length = i - inword;
return true;
}
inword = -1;
}
}
else
{
if (isletter)
inword = i;
}
}
return false;
}
// indexer to get and set words of the containing document:
public string this[int index]
{
get
{
int start, length;
if (getword(document.textarray, 0, index, out start,
out length))
return new string(document.textarray, start, length);
else
throw new indexoutofrangeexception();
}
set
{
int start, length;
if (getword(document.textarray, 0, index, out start,
out length))
{
// replace the word at start/length with the
// string "value":
if (length == value.length)
{
array.copy(value.tochararray(), 0,
document.textarray, start, length);
}
else
{
char[] newtext =
new char[document.textarray.length +
value.length - length];
array.copy(document.textarray, 0, newtext,
0, start);
array.copy(value.tochararray(), 0, newtext,
start, value.length);
array.copy(document.textarray, start + length,
newtext, start + value.length,
document.textarray.length - start
- length);
document.textarray = newtext;
}
}
else
throw new indexoutofrangeexception();
}
}
// get the count of words in the containing document:
public int count
{
get
{
int count = 0, start = 0, length = 0;
while (getword(document.textarray, start + length, 0,
out start, out length))
++count;
return count;
}
}
}
// type allowing the document to be viewed like an "array"
// of characters:
public class charactercollection
{
readonly document document; // the containing document
internal charactercollection(document d)
{
document = d;
}
// indexer to get and set characters in the containing document:
public char this[int index]
{
get
{
return document.textarray[index];
}
set
{
document.textarray[index] = value;
}
}
// get the count of characters in the containing document:
public int count
{
get
{
return document.textarray.length;
}
}
}
// because the types of the fields have indexers,
// these fields appear as "indexed properties":
public readonly wordcollection words;
public readonly charactercollection characters;
private char[] textarray; // the text of the document.
public document(string initialtext)
{
textarray = initialtext.tochararray();
words = new wordcollection(this);
characters = new charactercollection(this);
}
public string text
{
get
{
return new string(textarray);
}
}
}
class test
{
static void main()
{
document d = new document(
"peter piper picked a peck of pickled peppers. how many pickled peppers did peter piper pick?"
);
// change word "peter" to "penelope":
for (int i = 0; i < d.words.count; ++i)
{
if (d.words[i] == "peter")
d.words[i] = "penelope";
}
// change character "p" to "p"
for (int i = 0; i < d.characters.count; ++i)
{
if (d.characters[i] == 'p')
d.characters[i] = 'p';
}
console.writeline(d.text);
}
}