I’ve posted a utility String class I wrote years ago for Axapta. I’ve also compiled and used it in Dynamics AX v4. It extends the rather limited built-in string functions with a number of other common string manipulations and comparisons like “endsWith”, “replace”, “split”, etc.
Categories
- .NET
- Apple
- Art
- BarCamp
- Beer
- Blogging
- Books
- C#
- Conversant
- CSS
- Dallas.rb
- DemoCampDallas
- Drupal
- Dynamics AX
- eBay
- Family and Friends
- Games
- Health
- HTML
- Humor
- Java
- Javascript
- lsrc2007
- Mac OS X
- Mac OS X Server
- Microformats
- Microsoft
- Misc
- Movies
- Music
- OpenXML
- Pictures
- Poetry
- Politics
- PyCon
- Python
- RailsConf
- Ringtones
- Ruby on Rails
- Servoy
- Slicehost
- Sports
- Technology
- TiVO
- TV
- Uncategorized
- Windows
- WordPress
- Work
- XML
- XSL:FO
Archives
- May 2012
- April 2012
- March 2012
- February 2012
- January 2012
- December 2011
- November 2011
- October 2011
- September 2011
- August 2011
- July 2011
- June 2011
- May 2011
- April 2011
- March 2011
- February 2011
- January 2011
- March 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- April 2009
- February 2009
- January 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006
- August 2006
- July 2006
- June 2006
- May 2006
- April 2006
- March 2006
- February 2006
- January 2006
- December 2005
- November 2005
- October 2005
- September 2005
- August 2005
- July 2005
- June 2005
- May 2005
- April 2005
- March 2005
- February 2005
- January 2005
- December 2004
- November 2004
- October 2004
- September 2004
- August 2004
- July 2004
- June 2004
- May 2004
- April 2004
- March 2004
- February 2004
- January 2004
- December 2003
- November 2003
- October 2003
- September 2003
- August 2003
- July 2003
- June 2003
- May 2003
- April 2003
- March 2003
- February 2003
- January 2003
- December 2002
- November 2002
- October 2002
- September 2002
- August 2002
- July 2002
- June 2002
- May 2002
- April 2002
- March 2002
- February 2002
- January 2002
- December 2001
- November 2001
- October 2001
- September 2001
- August 2001
- July 2001
- June 2001
- May 2001
- April 2001
- March 2001
- February 2001
- January 2001
- December 2000
- November 2000
- October 2000
- September 2000
- August 2000
- July 2000
- June 2000
- May 2000
- April 2000
- March 2000
Hi Greg, love the String class and have subscribed to your RSS.
It’s really helped with something I was doing.
I reckon there’s a bug or 2 (depending on your understanding of strscan) in the replaceAll method:
pos = strscan( s, findStr, pos + strlen( replStr ), strlen( s ) );
– 3rd arg. Shouldn’t this be pos + strlen(findStr) otherwise if replStr is longer than findStr and findStr occurs close together we’ll skip over the 2nd quick occurrence.
– 4th arg should be strlen(s) – (pos + strlen(replStr)) ?
Anyhoo, I was using this on a mega string (150,000 char long result from an xsl transform) with lots of occurrences of the findStr in it and it was pretty darned slow. Caching the strlens in replaceAll saved about 10% but that was still quite slow.
There’s probably all sorts of reasons why the following shouldn’t be used but according to the profiler it’s about 40% quicker:
static str replaceAllTest2( str s, str findStr, str replStr)
{
int findStrLen = strlen(findStr);
int sLen = strlen(s);
int pos = strscan(s, findStr, 1, sLen);
str opStr = “”;
int lastPos = 1;
;
while(pos > 0)
{
opStr += substr(s, lastPos, pos – lastPos);
opStr += replStr;
lastPos = pos + findStrLen;
pos = strscan(s, findStr, lastPos, sLen – lastPos);
}
if (lastPos != sLen)
{
opStr += substr(s, lastPos, sLen – lastPos);
}
return opStr;
}
It’d be interesting to write a C# version and try that out for speed but deadlines threaten
Cheers
Chris Rothery
Hey, Chris, thanks for the comments. I’d imagine any of these would be pretty slow on a large string. I made on efforts to optimize — and, frankly, X++ isn’t a real smoker.
I’ll take a look at the bugs. I think I may have made some changes since the version that’s up here — I probably need to update. If you’re on AX v4, you should look at using .NET directly from X++. You’re manipulations will be a lot quicker.
Of course, I also am wondering why you’re doing string manipulation on the results of an XSL transform — maybe you should look at tweaking your stylesheet to get the results you want?
greg.
Thanks for the reply Greg.
I might be using a rocket launcher to kill a gnat but the reason I’ve ended up doing what I’m doing is to interface with a legacy system that has a fixed file format (feel free to skip to the bottom juicy bit now).
I’m using AX 4.0 and have written some classes to extend AIF file system adapter so that once the xml file pops out, we can transform that xml into the specific format (AIF pipeline xsl transforms were causing trouble with needing to remain xml in format and match schemas etc).
That’s all working but the specific format we’re generating has tags with in it. To get my xsl file to import into the repository we had to use < etc to stop it complaining that our xsl file was rubbish. That meant that those replacements came out in the final file rather than etc.
In the cold light of day, I agreed with you that I should try and sort the xsl but try as I might I couldn’t so I went back to processing the string result of the transform before writing it.
Long story short it’s now working beautifully (and ridiculously quickly!) using .Net directly (something I am only just getting into and was scared of but am going go persue now I’ve seen these results):
/*
replace the all occurances of “findStr” with “replStr” in “s”
*/
static str replaceAllTest3( str s, str findStr, str replStr)
{
// BP Deviation Documented
System.Text.StringBuilder sb = new System.Text.StringBuilder(s);
;
sb.Replace(findStr, replStr);
return sb.ToString();
}
According to the Dynamics profiler, the original replaceAll clocked about 3 million ‘ticks’. I got that down by about 40% but the Test3 above clocks in at a mere 33,000 ticks!!!
Amazed, happy, you name it, I’m experiencing the emotion right now
Thanks for your help and keep up the good work
Chris
Oh and…
I’m 99% sure I was being a moron on my 1st comment re the 3rd arg to the strscan line and it should be ‘pos + strlen(replStr)’.
Thanks a whole lot for the classes, Greg!
You’ve just spared me a bunch of time. Thanks again. Greets from Hungary
I searched on google and I had a hard time located the right info….until I found your blog.
Surly:
static str dbsReplaceString(str _inString, str _search, str _replace)
{
int pos = strScan(_inString, _search, 1, strLen(_inString))
;
if (!pos)
return _inString;
else
return subStr(_inString, 1, pos – 1) + _replace + substr(_inString, pos + strLen(_search), strLen(_inString));
}
Or am I missing something?
I meant:
static str dbsReplaceString(str _inString, str _search, str _replace)
{
int pos = strScan(_inString, _search, 1, strLen(_inString))
;
if (!pos)
return _inString;
else
return dbsLib::dbsReplaceString(subStr(_inString, 1, pos – 1) + _replace + substr(_inString, pos + strLen(_search), strLen(_inString)), _search, _replace);
}
thanks from Mexico