Re: Does gtk2 provide a case 'in'-sensitive text search via 'gtk_text_iter_..._search'?



On 02/17/2017 08:26 PM, cecashon aol com wrote:
David,

I asked a question about this on the gtk-devel-list

https://mail.gnome.org/archives/gtk-devel-list/2017-January/msg00018.html

last month. A lot I didn't know about this. For UTF-8 it is a bit complicated
even for English. For GTK's case in-sensitive search they use a casefold
function and a normalizing function. This way you can do a case in-sensitive
search on strings with ligatures and accents. If you are just sticking with
asci english chars then just converting and comparing case should work. There
is a bit more to it though for UTF-8 and unicode chars.

I worked on this a little bit so that I could understand it better. My last
attempt was

https://github.com/cecashon/OrderedSetVelociRaptor/blob/master/Misc/Csamples/search_textbuffer4.c

The GTK developers are working on GTK4. GTK3.22 should be stable for 3. GTK2
or 3 is fine with me.

Eric


Eric,

  After working with it a bit more, I encapsulated the forward and reverse
case-insensitive search functions for use without gtksourceview. They are part
of a little editor project I put together at:
https://github.com/drankinatty/gtkwrite

  The functions are:

/** case insensitive forward search for implementation without
 *  GtkSourceView.
 */
gboolean gtk_text_iter_forward_search_nocase (GtkTextIter *iter,
                                            const gchar *text,
                                            GtkTextSearchFlags flags,
                                            GtkTextIter *mstart,
                                            GtkTextIter *mend)
{
    gunichar c;
    gchar *lctext = g_strdup (text);   /* copy text */
    gsize textlen = g_strlen (text);   /* get length */

    str2lower (lctext);

    for (;;) {              /* iterate over all chars in range */

        gsize len = textlen;               /* get char at iter */
        c = g_unichar_tolower (gtk_text_iter_get_char (iter));

        if (c == (gunichar)lctext[0]) /* compare 1st in lctext */
        {
            *mstart = *iter;      /* set start iter to current */

            for (gsize i = 0; i < len; i++)
            {
                c = g_unichar_tolower (gtk_text_iter_get_char (iter));

                /* compare/advance -- order IS important */
                if (c != (gunichar)lctext[i] ||
                    !gtk_text_iter_forward_char (iter))
                    goto next;              /* start next search */
            }
            *mend = *iter;                  /* set end iter */
            if (lctext) g_free (lctext);    /* free lctext  */
            return TRUE;                    /* return true  */
        }
        next:;  /* if at end of selecton break */
        if (!gtk_text_iter_forward_char (iter))
            break;
    }
    if (lctext) g_free (lctext);    /* free lctext */

    if (mstart || mend || flags) {}

    return FALSE;
}

/** case insensitive backward search for implementation without
 *  GtkSourceView.
 */
gboolean gtk_text_iter_backward_search_nocase (GtkTextIter *iter,
                                            const gchar *text,
                                            GtkTextSearchFlags flags,
                                            GtkTextIter *mstart,
                                            GtkTextIter *mend)
{
    gunichar c;
    gchar *lctext = g_strdup (text);   /* copy text */
    gsize textlen = g_strlen (text);   /* get length */

    str2lower (lctext);     /* convert to lower-case */
    *mend = *iter;        /* initialize end iterator */

    while (gtk_text_iter_backward_char (iter)) {

        gsize len = textlen - 1;  /* index for last in lctext */
        c = g_unichar_tolower (gtk_text_iter_get_char (iter));

        if (c == (gunichar)lctext[len]) /* initial comparison */
        {
            /* iterate over remaining chars in lctext/compare */
            while (len-- && gtk_text_iter_backward_char (iter))
            {
                c = g_unichar_tolower (gtk_text_iter_get_char (iter));

                if (c != (gunichar)lctext[len]) {
                    /* reset iter to right of char */
                    gtk_text_iter_forward_char (iter);
                    goto prev;
                }
            }
            *mstart = *iter; /* set start iter before last char */
            if (lctext) g_free (lctext);        /* free lctext */
            return TRUE;                    /* return success */
        }
        prev:;
        *mend = *iter;   /* set end iter after next search char */
    }
    if (lctext) g_free (lctext);    /* free lctext */

    if (mstart || mend || flags) {}

    return FALSE;   /* no match */
}

  Implementation is using the cpp #define HAVESOURCEVIEW for compilation
purposes, e.g.

        /* case sensitive forward/reverse search from iter for 'text' setting
         * iters mstart & mend pointing to first & last char in matched text.
         */
        if (app->optback) {     /* search backward */
            if (app->optcase) { /* case sensitive  */
                found = gtk_text_iter_backward_search (&iter, text, 0,
                                                    &mstart, &mend, NULL);
            }
            else {  /* case insensitive backwards search */
#ifdef HAVESOURCEVIEW
                found = gtk_source_iter_backward_search (&iter, text,

GTK_SOURCE_SEARCH_CASE_INSENSITIVE,
                                                    &mstart, &mend, NULL);
#else
                found = gtk_text_iter_backward_search_nocase (&iter, text, 0,
                                                            &mstart, &mend);
#endif
            }
        }
        else {                  /* search forward */
            if (app->optcase) { /* case sensitive  */
                found = gtk_text_iter_forward_search (&iter, text, 0,
                                                    &mstart, &mend, NULL);
            }
            else {  /* case insensitive forward search */
#ifdef HAVESOURCEVIEW
                found = gtk_source_iter_forward_search (&iter, text,

GTK_SOURCE_SEARCH_CASE_INSENSITIVE,
                                                    &mstart, &mend, NULL);
#else
                found = gtk_text_iter_forward_search_nocase (&iter, text, 0,
                                                            &mstart, &mend);
#endif
            }
        }

  Hope this can help someone else.


-- 
David C. Rankin, J.D.,P.E.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]