1 module nxt.quoting;
2 
3 import nxt.array_traits : isCharArray;
4 
5 Chars[] quotedWords(Chars)(Chars s,
6 						   const scope string quoteBeginChar = `"`,
7 						   const scope string quoteEndChar = `"`)
8 if (isCharArray!Chars)
9 {
10 	typeof(return) words;
11 	import std.array : array;
12 	import nxt.splitter_ex : splitterASCIIAmong;
13 	import std.algorithm : filter;
14 	import std.string : indexOf, lastIndexOf;
15 	import std.range.primitives : empty;
16 	while (!s.empty)
17 	{
18 		auto quoteBeginI = s.indexOf(quoteBeginChar);
19 		if (quoteBeginI >= 0)
20 		{
21 			auto currI = quoteBeginI;
22 
23 			auto prefixBeginI = s[0 .. currI].lastIndexOf(' ');
24 			if (prefixBeginI >= 0)
25 			{
26 				currI = prefixBeginI + 1;
27 			}
28 
29 			words ~= s[0 .. currI].splitterASCIIAmong!(' ')
30 								  .filter!(a => !a.empty)
31 								  .array;
32 
33 			auto quoteEndI = s[quoteBeginI + 1 .. $].indexOf(quoteEndChar) + quoteBeginI + 1;
34 			auto suffixEndI = s[quoteEndI + 1 .. $].indexOf(' ');
35 			if (suffixEndI >= 0)
36 			{
37 				quoteEndI = quoteEndI + suffixEndI;
38 			}
39 			words ~= s[currI .. quoteEndI + 1];
40 			s = s[quoteEndI + 1 .. $];
41 		}
42 		else
43 		{
44 			words ~= s.splitterASCIIAmong!(' ')
45 					  .filter!(a => !a.empty)
46 					  .array;
47 			s = [];
48 		}
49 	}
50 	return words;
51 }
52 
53 ///
54 @system pure unittest {
55 	import std.stdio;
56 	import std.algorithm.comparison : equal;
57 	const t = `verb:is   noun:"New York" a noun:"big  city"@en `;
58 	const x = t.quotedWords;
59 	const xs = [`verb:is`, `noun:"New York"`, `a`, `noun:"big  city"@en`];
60 	assert(equal(x, xs));
61 	/+ TODO: assert(equal(` verb:is   name:"New York"@en article:a noun:"big  city"@en `.quotedWords, +/
62 	//			  [`verb:is`, `name:"New York"@en`, `article:a`, `noun:"big  city"@en`]));
63 }