How to loop through characters of a string in D language?

russhy russhy_s at gmail.com
Sat Dec 11 14:42:53 UTC 2021


Here is mine

- 0 allocations

- configurable

- let's you use it how you wish

- fast


```D
import std;
void main()
{
     string a = "abc;def;ab";
     writeln("a => ", a);

     foreach(item; split(a, ';'))
         writeln("\t", item);


     string b = "abc;    def   ;ab";
     writeln("a => ", b);

     foreach(item; split(b, ';', SplitOption.TRIM))
         writeln("\t", item);


     string c= "abc;    ;       ;def   ;ab";
     writeln("a => ",c);

     foreach(item; split(c, ';', SplitOption.TRIM | 
SplitOption.REMOVE_EMPTY))
         writeln("\t", item);
}

SplitIterator!T split(T)(const(T)[] buffer, const(T) delimiter, 
SplitOption option = SplitOption.NONE)
{
     return SplitIterator!T(buffer, delimiter, option);
}

struct SplitIterator(T)
{
     const(T)[] buffer;
     const(T) delimiter;
     SplitOption option;
     int index = 0;

	int count()
	{
		int c = 0;
		foreach(line; this)
		{
			c++;
		}
		index = 0;
		return c;
	}

	const(T) get(int index)
	{
		return buffer[index];
	}
	
     int opApply(scope int delegate(const(T)[]) dg)
     {
         auto length = buffer.length;
         for (int i = 0; i < length; i++)
         {
             if (buffer[i] == '\0')
             {
                 length = i;
                 break;
             }
         }

         int result = 0;
         for (int i = index; i < length; i++)
         {
             int entry(int start, int end)
             {
                 // trim only if we got something
                 if ((end - start > 0) && (option & 
SplitOption.TRIM))
                 {
                     for (int j = start; j < end; j++)
                         if (buffer[j] == ' ')
                             start += 1;
                         else
                             break;
                     for (int k = end; k >= start; k--)
                         if (buffer[k - 1] == ' ')
                             end -= 1;
                         else
                             break;
					
					// nothing left
					if(start >= end) return 0;
                 }

				//printf("%i to %i :: %i :: total: %lu\n", start, end, index, 
buffer.length);
                 return dg(buffer[start .. end]) != 0;
             }

             auto c = buffer[i];
             if (c == delimiter)
             {
                 if (i == index && (option & 
SplitOption.REMOVE_EMPTY))
                 {
                     // skip if we keep finding the delimiter
                     index = i + 1;
                     continue;
                 }

                 if ((result = entry(index, i)) != 0)
                     break;

                 // skip delimiter for next result
                 index = i + 1;
             }

             // handle what's left
             if ((i + 1) == length)
             {
                 result = entry(index, i + 1);
             }
         }
         return result;
     }

	// copy from above, only replace if above has changed
     int opApply(scope int delegate(int, const(T)[]) dg)
     {
         auto length = buffer.length;
         for (int i = 0; i < length; i++)
         {
             if (buffer[i] == '\0')
             {
                 length = i;
                 break;
             }
         }

		int n = 0;
         int result = 0;
         for (int i = index; i < length; i++)
         {
             int entry(int start, int end)
             {
                 // trim only if we got something
                 if ((end - start > 0) && (option & 
SplitOption.TRIM))
                 {
                     for (int j = start; j < end; j++)
                         if (buffer[j] == ' ')
                             start += 1;
                         else
                             break;
                     for (int k = end; k >= start; k--)
                         if (buffer[k - 1] == ' ')
                             end -= 1;
                         else
                             break;
					
					// nothing left
					if(start >= end) return 0;
                 }

				//printf("%i to %i :: %i :: total: %lu\n", start, end, index, 
buffer.length);
                 return dg(n++, buffer[start .. end]) != 0;
             }

             auto c = buffer[i];
             if (c == delimiter)
             {
                 if (i == index && (option & 
SplitOption.REMOVE_EMPTY))
                 {
                     // skip if we keep finding the delimiter
                     index = i + 1;
                     continue;
                 }

                 if ((result = entry(index, i)) != 0)
                     break;

                 // skip delimiter for next result
                 index = i + 1;
             }

             // handle what's left
             if ((i + 1) == length)
             {
                 result = entry(index, i + 1);
             }
         }
         return result;
     }
}


enum SplitOption
{
     NONE = 0,
     REMOVE_EMPTY = 1,
     TRIM = 2
}

```


More information about the Digitalmars-d-learn mailing list