counting characters in strings

For the Compleat Fan
Locked
cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

counting characters in strings

Post by cormullion »

I wonder if there's a better way to count the number of occurrences of a character in a string, rather than convert both to lists first:

Code: Select all

(count (list "a") (explode a)
Nothing wrong with it other than it being a bit roundabout! ;-)

m i c h a e l
Posts: 394
Joined: Wed Apr 26, 2006 3:37 am
Location: Oregon, USA
Contact:

Post by m i c h a e l »

cormullion wrote: I wonder if there's a better way to count the number of occurrences of a character in a string, rather than convert both to lists first:
I'll playfully assume you did not mean this:

Code: Select all

> (set 'a (dup "abcdefg" 5))
"abcdefgabcdefgabcdefgabcdefgabcdefg"
> (define (num-chars s) (count (args) (explode s)))
(lambda (s) (count (args) (explode s)))
> (num-chars a "b" "g" "a" "x")
(5 5 5 0)
> _
But something more like this:

Code: Select all

> _ 
Imagine the prompt blinking away, patiently waiting.

"Where is michael?", the prompt quietly thinks to itself after some time passes.

Code: Select all

> _ 
After a while, the prompt blurts out, "Here he is! Must have been off in the manual, seeing how to do it."

Code: Select all

> _ 
"Now he's pressing the . . . Control key? Control key. Why would he . . . Not D! Not Control-[click]"

Code: Select all

> ^D
bash> _
Every way I tried to finagle it, lists ended up crashing the party. I suspect something like the string buffer functions would be the tool of choice, but I'll leave the answer up to one of the club's newrus (newLISP gurus ;-)

m i c h a e l

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

m i c h a e l wrote:
cormullion wrote: I wonder if there's a better way to count the number of occurrences of a character in a string, rather than convert both to lists first:
I'll playfully assume you did not mean this:

Code: Select all

> (set 'a (dup "abcdefg" 5))
"abcdefgabcdefgabcdefgabcdefgabcdefg"
> (define (num-chars s) (count (args) (explode s)))
(lambda (s) (count (args) (explode s)))
> (num-chars a "b" "g" "a" "x")
(5 5 5 0)
> _
Correct. Converting the strings to lists is indeed the 'roundabout'-ness of which I spoke.
m i c h a e l wrote: But something more like this:

Code: Select all

> _ 
Imagine the prompt blinking away, patiently waiting.

"Where is michael?", the prompt quietly thinks to itself after some time passes.

Code: Select all

> _ 
After a while, the prompt blurts out, "Here he is! Must have been off in the manual, seeing how to do it."

Code: Select all

> _ 
"Now he's pressing the . . . Control key? Control key. Why would he . . . Not D! Not Control-[click]"

Code: Select all

> ^D
bash> _
Every way I tried to finagle it, lists ended up crashing the party. I suspect something like the string buffer functions would be the tool of choice, but I'll leave the answer up to one of the club's newrus (newLISP gurus ;-)

m i c h a e l
Um, yes. What substances have you been ingesting today? ;-)

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Cormullion's function is the best method of counting characters in a string:

Code: Select all

(define (num-chars s) 
    (count (args) (explode s)))
but just as an interesting exercise I wrote this function counting characters in a string without breaking it up:

Code: Select all

(define (num-chars str)
    (let (result)
        (dolist (c (args))
            (replace c str "")
            (push $0 result -1))
        result))

> (num-chars a  "b" "g" "a" "x") 
(5 5 5 0)
> 
it uses the fact that replace puts the count of replacemenets into the system variable $0.

Lutz

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Yes, LUtz, that's a good idea!

My initial question was inspired in part by the fact that I couldn't remember whether 'count' was one of the set of functions that doesn't work for both lists and strings. It's a very pleasant aspect of newLISP that you can often use the same function for both lists and strings, and I had to look carefully in the manual before I realised that 'count' was strictly list-only.

It's no problem!

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

I think it was m i c h a e l ' s function. I may have mis-double-re-un-counter-quoted him....

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

It's a very pleasant aspect of newLISP that you can often use the same function for both lists and strings, and I had to look carefully in the manual before I realised that 'count' was strictly list-only.
... and slowly I am trying to round out the API and make list-only functions work on strings too. The last addition to work on strings was 'push/pop'; 'count', 'rotate' and 'member' are the next and I probably will stop there. For some functions it just doesn't make much sense, like the set functions 'intersect', 'difference' and 'unique' which will always only work on lists or functions working on associations like 'assoc' and 'replace-assoc'.

'count' could also be able to count whole substrings, not only characters and perhaps accept regular expressions ... we will see.

Lutz

Locked