One-liner for counting the number of occurrences of $char in $string

Jan 25, 2011 at 8:34 PM

I found this on Twitter via @greystate and thought it add good value to this project.  I asked if you could add it to this project and he didn't have a problem with it.

<xsl:value-of select="string-length($string) - string-length(translate($string, $char, ''))" />

Coordinator
Jan 25, 2011 at 8:44 PM

Thanks, Matt!

Deceptively simple, yet I could see how it might be useful.

It would be nice to generalize it to work regardless of the length of $char. In other words, to count the number of occurrences of a string within another string. Want to tackle that?

M.

Jan 25, 2011 at 9:30 PM

I'll take it on... I think it has great value in search results or querying wiki pages for hits on words.  Well, that's how I plan on using it initially. :)

Feb 1, 2011 at 12:49 AM

Better late than never, eh?  It's been tough to do work given the fact that I'm living in a hotel currently. :)  Here's what I've come up with, I hope it's on point.

<xsl:call-template name="CharCount">
<xsl:with-param name="String" select="@Body"/>
<xsl:with-param name="Char" select="'SharePoint'" />
<xsl:with-param name="Counter" select="0" />
</xsl:call-template>	


<xsl:template name="CharCount">
<xsl:param name="String" />
<xsl:param name="Char" />
<xsl:param name="Counter" />

<xsl:choose>
<xsl:when test="contains($String, $Char)">
<xsl:variable name="Before" select="substring-before($String, $Char)" />
<xsl:variable name="After" select="substring-after($String, $Char)" />

<xsl:call-template name="CharCount">
<xsl:with-param name="String" select="concat($Before, ' ', $After)"/>
<xsl:with-param name="Char" select="$Char" />
<xsl:with-param name="Counter" select="$Counter + 1" />
</xsl:call-template>
</xsl:when>

<xsl:otherwise>
<xsl:value-of select="$Counter" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>


Cheers,

Matt

Coordinator
Feb 1, 2011 at 1:42 AM

Matt:

I think you *could* get into infinite recursion (depending on the value of $Char) if you have the template call itself with

<xsl:with-param name="String" select="concat($Before, ' ', $After)"/>

Since you've already found the match, you can just call with

<xsl:with-param name="String" select="$After"/>

Also, $Char isn't a good parameter name, since we're looking for a substring. How about $SubString and the name SubStringCount for the template?

M.

Feb 1, 2011 at 2:07 AM
Edited Feb 1, 2011 at 4:06 PM

I added a space to try to head that off, but I see your angle and it's much better than my approach.  Let's go for it.  All of the names, to me, are just names.  If you feel the variables are better one way or another, I won't lose any sleep if you change them. :)

Cheers,

Matt

P.S. I've just tried it with the changes and the template works great.