Nowadays there are plenty of services available on the internet, e.g. for searching street names. This tutorial shows us how to implement a searchhelp for street names that doesn't require an active internet connection.

Starting point is a list with all streets in Germany: strassen_osm.txt:
The file size is about 1.50 MB and contains around 96000 entries.

The GuiXT script for entering the name of the street (first letters are sufficient), result table etc. looks like this:

GuiXT

pushbutton (2,110) "search" process="search_street_va03.txt"
pushbutton (2,115) "choose" process="use_street_va03.txt"
inputfield (2,84) "Search for street" (3,100) size="25" name="searchstreet"
inputfield (3,84) "Results:" (3,100) size="25" name="chosenstreet"
Table (4,84) (17,140) name="streettab" title="Streets rows=10 -singlerowselection
Column "Street name" size=40 name="streets"

In the InputScript "search_street_va03.txt" we call a .NET (VB/C#) function and then fill the table on the SAP screen with the data that we recieve from the function. (We restrict the results to a maximum of 10 rows.)

GuiXT
// Clear table
Set "V[streettab.*]"  ""
callvb result = utils.StreetSearcher.FindStreets "&V[searchstreet]"
if not V[result=0]
  message "&V[result]"
endif

Set V[i] 1
Set V[max_streets] 10
label start
copytext fromText="streets_results&V[i]" toString="streetTemp"
Set "V[streettab.cell.streets.&V[i]]" "&V[streetTemp]" 
Set V[i] &V[i] + 1
if V[i=&V[max_streets]]
  goto endloop
endif
goto start
label endloop

In the function "find_streets" of class "utilities" of our class library "tutorials.dll" we search the textfile for any matching entry. A match means that the street name starts with the letters that the user has given. Then we put those results into a GuiXT textvariable for the previous InputSript:

using guinet;
using System;
using System.Collections.Generic;
using System.IO;

namespace utils
{
    internal class MyStringComparer :
        IComparer<string>
    {
        public int Compare(string x, string y)
        {
            if (x == null && y == null) return 0;
            if (x == null) return -1;
            if (y == null) return 1;

            // Compare full strings (case-insensitive)
            // This allows proper binary search and
            // sorting
            return string.Compare(x, y,
                StringComparison
                    .CurrentCultureIgnoreCase);
        }
    }

    public class StreetSearcher
    {
        private bool streets_read = false;
        private string[] streets;
        private readonly MyStringComparer comparer =
            new MyStringComparer();

        public string FindStreets(string search)
        {
            guixt g = new guixt();
            try
            {
                if (string.IsNullOrWhiteSpace(search))
                {
                    return "Sucheingabe ist leer";
                }

                // Load and sort streets on first use
                if (!streets_read)
                {
                    string filePath =
                        Path.Combine("c:\\", "temp",
                        "strassen_osm.txt");

                    if (!File.Exists(filePath))
                    {
                        return
                            $"Datei nicht gefunden: " +
                            $"{filePath}";
                    }

                    streets =
                        File.ReadAllLines(filePath);

                    Array.Sort(streets, comparer);

                    streets_read = true;
                }

                // Clear result cells (1-10)
                for (int c = 1; c <= 10; c++)
                {
                    g.SetText(
                        "streets_results" +
                        c.ToString(), "");
                }

                // Perform binary search with
                // prefix matching
                int index = BinarySearchPrefix(
                    streets, search, comparer);

                if (index < 0)
                {
                    return "Kein Eintrag gefunden";
                }

                // Find the start of all matching
                // entries
                int startIndex = index;
                while (startIndex > 0 &&
                       StartsWithIgnoreCase(
                           streets[startIndex - 1],
                           search))
                {
                    startIndex--;
                }

                // Display up to 10 matching results
                int resultCount = 0;
                for (int c = startIndex;
                     c < streets.Length &&
                     resultCount < 10; c++)
                {
                    if (StartsWithIgnoreCase(
                        streets[c], search))
                    {
                        g.SetText(
                            "streets_results" +
                            (resultCount + 1)
                                .ToString(),
                            streets[c]);
                        resultCount++;
                    }
                    else if (resultCount > 0)
                    {
                        // Stop when found matches
                        // but hit non-match
                        break;
                    }
                }

                return resultCount > 0 ? "0" :
                    "Kein Eintrag gefunden";
            }
            catch (Exception ex)
            {
                return $"Fehler: {ex.Message}";
            }
        }

        /// <summary>
        /// Performs binary search for entries
        /// starting with the search string
        /// (case-insensitive).
        /// </summary>
        private int BinarySearchPrefix(
            string[] array, string search,
            IComparer<string> comp)
        {
            int left = 0;
            int right = array.Length - 1;

            while (left <= right)
            {
                int mid = left +
                    (right - left) / 2;
                int cmp = comp.Compare(
                    array[mid], search);

                // Check if entry starts with
                // search term
                if (StartsWithIgnoreCase(
                    array[mid], search))
                {
                    return mid;
                }

                // If string at mid is less than
                // search, search right
                if (cmp < 0)
                {
                    left = mid + 1;
                }
                else
                {
                    right = mid - 1;
                }
            }

            return -1;
        }

        /// <summary>
        /// Case-insensitive prefix matching
        /// helper.
        /// </summary>
        private bool StartsWithIgnoreCase(
            string source, string prefix)
        {
            if (source == null ||
                prefix == null)
                return false;

            return source.StartsWith(prefix,
                StringComparison
                    .CurrentCultureIgnoreCase);
        }
    }
}

Notes:
 
  - On using sorted lists we recommend you use a binary search (instead of linear search) to significantly reduce the search time.
  - The textfile containing the street names needs to be read only once from the hard disk and is then available in memory for future requests.

The user can  then mark any row of the result table and on clicking "choose" the name of the chosen street is put into an InputField:

GuiXT

Set V[i] "1"
label selection
if  V[streettab.stat.rowselection.&V[i]=X] 
  set V[chosenstreet] "&V[streettab.cell.streets.&V[i]]"
endif
Set V[i] "&V[i]" + 1
if not V[i=11]
  goto selection
endif

return


Result:

 

Download text file scripts (ZIP)