We use our own custom library for string manipulation, written by acaos. My favorite is GetFirstSubstring, which lets you loop through concatenated strings with dividers, making them into pseudolists. I did a quick snatchngrab of string functions - not sure all the declarations have matching functions and vice versa, lmk if you want more, or examples of usage:
/* Replace the first (or all) occurrence of sFind in sStr with sRepl. */
string ReplaceString (string sStr, string sFind, string sRepl, int bAll=FALSE, int nLen=-1);
/* Return the specified digit nDigit of nInt. nDigit is the number of
* powers of 10 to use (hence, 0 = 1s, 1 = 10s, 2 = 100s, etc). */
int GetIntegerDigit (int nInt, int nDigit);
/* Set the specified digit nDigit of nInt. */
int SetIntegerDigit (int nInt, int nDigit, int nValue);
/* Return an IntList struct containing all the digits of nInt. */
struct IntList GetDigitList (int nInt);
/* Get a random floating-point number in the range [-1.0, 1.0]. If fRange
* is specified, a random number in the range [0.0, fRange] will be returned. */
float RandomFloat (float fRange=0.0);
/* Return the substring at the given index nIndex of sString, separating
* sString with sSep. */
string GetStringSubString (string sString, int nIndex, string sSep=" ");
/* Return the number of substrings sString would have if it were separated
* by sSep. */
int GetStringSubStrings (string sString, string sSep=" ");
/* Return a random string of sString separated by sSep. */
string GetRandomSubString (string sString, string sSep=" ");
/* Return a SubString struct containing the first substring of sString
* separated by sSep, as well as the remainder of sString. The idiom
* would be:
*
* struct SubString ss;
*
* ss.rest = sString;
*
* while (ss.rest != "") {
* ss = GetFirstSubString(ss.rest);
*
* (do things here)
* }
*/
struct SubString GetFirstSubString (string sString, string sSep = " ");
/* Return a StringList struct containing strings extracted from sString
* separated by sSep. */
struct StringList GetStringList (string sString, string sSep=" ", int nLimit=16);
/* Return an IntList struct containing integers extracted from sString
* separated by sSep. */
struct IntList GetIntList (string sString, string sSep=" ", int nLimit=10);
/* Justify a string to a given number of pixels wide. */
string JustifyString (string sStr, int nPixelWidth, int bRight=FALSE, int nFont=0, string sJustifyWith=" ");
/* Return either the resref or playername of oObject. */
string GetObjectString (object oObject);
/* Return vPos in string form X, Y, Z. */
string GetPositionStringFromVector (vector vPos);
/* Return the position of lLoc in string form [X, Y, Z | F] */
string GetPositionStringFromLocation (location lLoc);
/* Return the position of oObject in string form [X, Y, Z | F] */
string GetPositionString (object oObject);
string ReplaceString (string sStr, string sFind, string sRepl, int bAll=FALSE, int nLen=-1) {
int nPos = FindSubString(sStr, sFind);
if (nPos < 0 || sStr == "")
return sStr;
if (nLen < 0)
nLen = GetStringLength(sFind);
do {
sStr = GetStringLeft(sStr, nPos) + sRepl +
GetStringRight(sStr, GetStringLength(sStr) - (nPos + nLen));
if (!bAll)
break;
nPos = FindSubString(sStr, sFind);
} while (nPos >= 0);
return sStr;
}
int GetIntegerDigit (int nInt, int nDigit) {
switch (nDigit) {
case 0: nDigit = 1; break;
case 1: nDigit = 10; break;
case 2: nDigit = 100; break;
case 3: nDigit = 1000; break;
case 4: nDigit = 10000; break;
case 5: nDigit = 100000; break;
case 6: nDigit = 1000000; break;
case 7: nDigit = 10000000; break;
case 8: nDigit = 100000000; break;
case 9: nDigit = 1000000000; break;
default:
return 0;
}
return ((nInt / nDigit) % 10);
}
int SetIntegerDigit (int nInt, int nDigit, int nValue) {
if (nValue < 0)
nValue = 0;
else if (nValue > 9)
nValue = 9;
switch (nDigit) {
case 0: nDigit = 1; break;
case 1: nDigit = 10; break;
case 2: nDigit = 100; break;
case 3: nDigit = 1000; break;
case 4: nDigit = 10000; break;
case 5: nDigit = 100000; break;
case 6: nDigit = 1000000; break;
case 7: nDigit = 10000000; break;
case 8: nDigit = 100000000; break;
case 9: nDigit = 1000000000; break;
default:
return 0;
}
nInt -= ((nInt / nDigit) % 10) * nDigit;
nInt += nValue * nDigit;
return nInt;
}
struct IntList GetDigitList (int nInt) {
struct IntList ret;
ret.i0 = (nInt % 10);
ret.i1 = (nInt /= 10) % 10;
ret.i2 = (nInt /= 10) % 10;
ret.i3 = (nInt /= 10) % 10;
ret.i4 = (nInt /= 10) % 10;
ret.i5 = (nInt /= 10) % 10;
ret.i6 = (nInt /= 10) % 10;
ret.i7 = (nInt /= 10) % 10;
ret.i8 = (nInt /= 10) % 10;
ret.i9 = (nInt /= 10) % 10;
return ret;
}
float RandomFloat (float fRange=0.0) {
if (fRange > 0.0)
return (Random(FloatToInt(fRange * 1000)) / 1000.0);
return ((Random(10000001) - 5000000) / 5000000.0);
}
float RandomNormal (float fStdDev=1.0, float fMean=0.0) {
float u1, u2, v1, v2, s;
do {
u1 = RandomFloat();
u2 = RandomFloat();
v1 = (2.0 * u1) - 1.0;
v2 = (2.0 * u2) - 1.0;
s = (v1 * v1) + (v2 * v2);
} while (s > 1.0);
return (sqrt((-2.0 * log(s)) / s) * v1 * fStdDev) + fMean;
}
string GetStringSubString (string sString, int nIndex, string sSep=" ") {
int nSep, nStart = 0, nSkip = GetStringLength(sSep);
while (nIndex-- > 0) {
nSep = FindSubString(sString, sSep, nStart);
if (nSep < 0)
return "";
nStart = nSep + nSkip;
}
if ((nSep = FindSubString(sString, sSep, nStart)) < 0)
nSep = GetStringLength(sString);
return GetSubString(sString, nStart, (nSep - nStart));
}
int GetStringSubStrings (string sString, string sSep=" ") {
int nCount = 1, nStart = 0;
int nSep = FindSubString(sString, sSep);
int nSkip = GetStringLength(sSep);
if (nSkip < 1)
return 1;
while (nSep >= 0) {
nCount++;
nSep = FindSubString(sString, sSep, nSep + nSkip);
}
return nCount;
}
string GetRandomSubString (string sString, string sSep=" ") {
int nCount = GetStringSubStrings(sString, sSep);
return GetStringSubString(sString, Random(nCount), sSep);
}
struct SubString GetFirstSubString (string sString, string sSep = " ") {
struct SubString ret;
int nSep = FindSubString(sString, sSep);
if (nSep < 0) {
ret.first = sString;
ret.rest = "";
return ret;
}
ret.first = GetStringLeft(sString, nSep);
ret.rest = GetStringRight(sString, GetStringLength(sString) - (nSep + GetStringLength(sSep)));
return ret;
}
struct StringList GetStringList (string sString, string sSep=" ", int nLimit=16) {
int nCount = 0, nSep = 0, nStart = 0;
int nSkip = GetStringLength(sSep);
int nLen = GetStringLength(sString);
struct StringList sl;
if (nSkip < 1) {
sl.size = 0;
return sl;
}
while (nSep < nLen && nCount < nLimit) {
nSep = FindSubString(sString, sSep, nStart);
if (nSep < 0)
nSep = nLen;
switch (nCount & 1) {
case 0: switch (nCount++) {
case 0: sl.s0 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 2: sl.s2 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 4: sl.s4 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 6: sl.s6 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 8: sl.s8 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 10: sl.s10 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 12: sl.s12 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 14: sl.s14 = GetSubString(sString, nStart, (nSep - nStart)); break;
}
break;
case 1: switch (nCount++) {
case 1: sl.s1 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 3: sl.s3 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 5: sl.s5 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 7: sl.s7 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 9: sl.s9 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 11: sl.s11 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 13: sl.s13 = GetSubString(sString, nStart, (nSep - nStart)); break;
case 15: sl.s15 = GetSubString(sString, nStart, (nSep - nStart)); break;
}
break;
}
nStart = nSep + nSkip;
}
sl.size = nCount;
return sl;
}
struct IntList GetIntList (string sString, string sSep=" ", int nLimit=10) {
int nCount = 0, nSep = 0, nStart = 0;
int nLen = GetStringLength(sString);
int nSkip = GetStringLength(sSep);
struct IntList il;
if (nSkip < 1) {
il.size = 0;
return il;
}
while (nSep < nLen && nCount < nLimit) {
nSep = FindSubString(sString, sSep, nStart);
if (nSep < 0)
nSep = nLen;
switch (nCount++) {
case 0: il.i0 = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
case 1: il.i1 = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
case 2: il.i2 = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
case 3: il.i3 = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
case 4: il.i4 = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
case 5: il.i5 = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
case 6: il.i6 = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
case 7: il.i7 = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
case 8: il.i8 = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
case 9: il.i9 = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
}
nStart = nSep + nSkip;
}
il.size = nCount;
return il;
}
string JustifyString (string sStr, int nPixelWidth, int bRight=FALSE, int nFont=0, string sJustifyWith=" ") {
int i, nSpace, nLen = GetStringLength(sStr), nWidth = nLen - 1;
string sWidths;
switch (nFont) {
case 0: /* normal */
nSpace = (sJustifyWith == "." ? 2 : 4);
sWidths = " 3 05 13 25 35 45 55 65 75 85 95 A7 B6 C6 D6 E5 F5 G7 H6 I1 J4 K6 L5 M7 N6 O7 P5 Q7 R6 S6 T5 U6 V7 W11 X6 Y7 Z6 a5 b5 c5 d5 e5 f3 g5 h5 i1 j2 k4 l1 m7 n5 o5 p5 q5 r3 s5 t2 u5 v5 w9 x5 y5 z5 !1 #5 $5 %9 &6 '1 (3 )3 *3 +5 ,1 -5 .1 /3 :1 ;1 <5 >5 ?5 @10 [2 ]2 ^5 {3 |1 }3 ~5";
/* double quote = 3 */
break;
case 1: /* high-resolution */
nSpace = (sJustifyWith == "." ? 3 : 5);
sWidths = " 4 07 14 27 37 48 57 67 77 87 97 A10 B8 C9 D9 E8 F8 G10 H8 I2 J6 K9 L8 M10 N8 O10 P8 Q10 R9 S8 T8 U8 V10 W14 X9 Y10 Z9 a7 b7 c6 d7 e7 f5 g7 h7 i2 j3 k7 l2 m10 n7 o7 p7 q7 r5 s6 t5 u7 v8 w10 x7 y8 z7 !2 #9 $8 %11 &9 '2 (4 )4 *6 +8 ,2 -5 .2 /5 :2 ;2 <7 >7 ?7 @13 [3 ]3 ^6 {4 |2 }4 ~8";
/* double quote = 4 */
break;
case 2: /* journal */
nSpace = (sJustifyWith == "." ? 3 : ;
sWidths = " 7 06 12 25 36 48 56 66 76 86 96 A9 B6 C10 D9 E6 F6 G9 H7 I2 J4 K7 L6 M10 N9 O10 P5 Q11 R7 S6 T9 U8 V10 W13 X9 Y9 Z9 a5 b7 c6 d7 e7 f7 g7 h6 i2 j4 k7 l2 m10 n6 o6 p7 q6 r4 s4 t7 u6 v6 w10 x6 y6 z6 !1 #8 $7 %9 &10 '2 (4 )4 *4 +6 ,2 -4 .2 /4 ?6 @8 [4 ]4 ^5 {5 }5 ~5";
/* double quote = 4 */
break;
default:
return sStr;
}
for (i = 0; i < nLen; i++) {
string sChar = GetSubString(sStr, i, 1);
int nCharPos = FindSubString(sWidths, " " + sChar);
if (nCharPos >= 0) {
int nCharWidth = StringToInt(GetSubString(sWidths, nCharPos + 2, 2));
nWidth += nCharWidth;
}
}
if (bRight) {
while (nWidth < nPixelWidth) {
sStr = sJustifyWith + sStr;
nWidth += nSpace;
}
} else {
while (nWidth < nPixelWidth) {
sStr = sStr + sJustifyWith;
nWidth += nSpace;
}
}
return sStr;
}
string GetObjectString (object oObject) {
if (GetIsPC(oObject))
return GetPCPlayerName(oObject);
return GetResRef(oObject);
}
string GetPositionStringFromVector (vector vPos) {
return FloatToString(vPos.x, 1, 2) + ", " +
FloatToString(vPos.y, 1, 2) + ", " +
FloatToString(vPos.z, 1, 2);
}
string GetPositionStringFromLocation (location lLoc) {
vector vPos = GetPositionFromLocation(lLoc);
return "[" + GetPositionStringFromVector(GetPositionFromLocation(lLoc)) +
" | " + FloatToString(GetFacingFromLocation(lLoc), 1, 0) + "]";
}
string GetPositionString (object oObject) {
return GetPositionStringFromLocation(GetLocation(oObject));
}
location GetLocationFromString (object oArea, string sLoc) {
float fFacing;
vector vVec;
vVec = Vector(StringToFloat(GetStringSubString(sLoc, 0, ",")),
StringToFloat(GetStringSubString(sLoc, 1, ",")),
StringToFloat(GetStringSubString(sLoc, 2, ",")));
fFacing = StringToFloat(GetStringSubString(sLoc, 3, ","));
return Location(oArea, vVec, fFacing);
}
Funky