• Welcome to OS2World OLD-STATIC-BACKUP Forum.
 

News:

This is an old OS2World backup forum for reference only. IT IS READ ONLY!!!

If you need help with OS/2 - eComStation visit http://www.os2world.com/forum

Main Menu

count occurances in a string and extract balanced xml tags

Started by jep, 2009.03.22, 20:23:22

Previous topic - Next topic

jep

Marked as: Easy
Hi,

It's sometimes necessary to count occurrences of a string within another string, and here's a little code I've written to do that.

COUNTSTR: PROCEDURE /* needle, haystack< <, startpos>, endpos> */
    IF ARG() < 2 THEN RETURN -1
    IF DATATYPE( ARG(3), 'W' ) THEN
        next = ARG(3)
    ELSE
        next = 1
    needle = ARG(1)
    haystack = ARG(2)
    IF DATATYPE( ARG(4), 'W' ) THEN
        haystack = SUBSTR( haystack, next, ABS( ARG(4) - next ) )
    next = 1
    count = 0
    DO WHILE next > 0
        next = POS( needle, haystack, next )
        IF next > 0 THEN DO
            next = next + LENGTH( needle )
            count = count + 1
        END
    END
RETURN count



If you try to use html pages or some other xml-like file format, it's very useful if you can specify the section you want to extract and not deal with things around, the function COUNTSTR above then come in handy to take care of some of the work.

xml_balanced_tags_parse: procedure /* xml-code, tag<, setting> */
    next = pos( '<'||translate( ARG(2)||ARG(3) ), translate( ARG(1) ) )
    if next = 0 then Return ARG(1)
    next = next + length( ARG(2)||ARG(3) ) + 2
    open_tag = next
    close_tag = pos( '</'||translate( ARG(2) ), translate( ARG(1) ), next )
    count = COUNTSTR( '<'||translate( ARG(2) ), translate( ARG(1) ), next, close_tag )
    do i = 1 to count
        next = close_tag + length( ARG(2) ) + 3
        close_tag = pos( '</'||translate( ARG(2) ), translate( ARG(1) ), next )
        count = count + COUNTSTR( '<'||translate( ARG(2) ), translate( ARG(1) ), next, close_tag )
    end
    if close_tag = 0 then end_tag = length( ARG(1) )
    else end_tag = close_tag - open_tag
Return substr( ARG(1), open_tag, max( 1, end_tag ) )


Example: retval = xml_balanced_tags_parse( xmlfile, 'div', ' style="color: blue;"' )

Please note that you have to specify the settings very accurately or it will ignore it and not find anything, that is, if something else may be present between "h1" and "style=..." in the example it will return nothing. It is possible to make it more relaxed/forgiving, but that is an exercise that I leave to you for the moment.

//Jan-Erik

jep

Hi All,

I've rewritten the code somewhat now that RobertM has posted an alternative version.
You may compare both to see what they have in common and what differ as well see what may be improved or just added to be more useful.

xml_balanced_tags_parse: procedure /* xml-code, tag<, setting> */
    upper_arg_1 = translate( ARG(1) )
    upper_arg_2 = translate( ARG(2) )
    upper_arg_3 = translate( ARG(3) )
    next = pos( '<'||upper_arg_2||upper_arg_3, upper_arg_1 )
    if next = 0 then Return ARG(1)
    next = next + length( upper_arg_2||upper_arg_3 ) + 2
    open_tag = next
    close_tag = pos( '</'||upper_arg_2, upper_arg_1, next )
    count = COUNTSTR( '<'||upper_arg_2, upper_arg_1, next, close_tag )
    do i = 1 to count
        next = close_tag + length( ARG(2) ) + 3
        close_tag = pos( '</'||upper_arg_2, upper_arg_1, next )
        count = count + COUNTSTR( '<'||upper_arg_2, upper_arg_1, next, close_tag )
    end
    if close_tag = 0 then end_tag = length( ARG(1) )
    else end_tag = close_tag - open_tag
Return substr( ARG(1), open_tag, max( 1, end_tag ) )


There are at least two differences between our versions.
Can you spot them?
What benefit do they provide?
Can you combine the scripts into a new version that is better?

//Jan-Erik