-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Class_StrSplitEnumerator.xpp
171 lines (142 loc) · 5.73 KB
/
Class_StrSplitEnumerator.xpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//
// https://github.com/mazzy-ax/SysUtil
//
// делит строку на подстроки, разделенные строкой delimiter
// Если maxSubstrings не ноль, то максимальная контейнера не будет превышать maxSubstrings.
// делает одну итерацию на всю исходную строку, если ни одного символа-разделителя не найдено.
//
// пример:
// StrSplitEnumerator::construct('ABC:=DEF:=GH',':=') => ['ABC','DEF','GH']
// StrSplitEnumerator::construct('ABC:=DEF:=GH',':=',2) => ['ABC','DEF:=GH']
// StrSplitEnumerator::construct('ABC:=DEF:=GH',':=',1) => ['ABC:=DEF:=GH']
//
class StrSplitEnumerator implements Enumerator
{
str string;
int stringLenPlus1;
str delimiterStr;
int delimiterLen;
int maxSubstrings;
int currentIdx; // индекс текущего чанка (не более, чем maxSubstrings)
int currentPos; // начальная позиция текущего чанка
int currentLen; // длина текущего чанка
int nextPos;
public anytype current()
{
// никаких проверок:
// substr вернет что-нибудь, если параметры странные. скорее всего пустую строку.
str ret = substr(string, currentPos, currentLen);
return ret;
}
public str definitionString()
{
return 'Str split enumerator';
}
// метод публичный, чтобы объект данного класса можно было создавать из classFactory и инициализировать из всевозможных unpack
// не вызывайте этот метод напрямую
public void init(str s, str _delimiter, int _maxSubstrings = 0)
{
string = s;
stringLenPlus1 = strlen(s) + 1;
delimiterStr = _delimiter;
delimiterLen = strlen(_delimiter);
maxSubstrings = _maxSubstrings;
this.reset();
}
// вычисляет параметры для метода current(): currentPos, currentLen и currentIdx
// currentIdx - сколько раз вызывался метод moveNext()
//
public boolean moveNext()
{
int pos;
;
currentIdx++;
currentPos = nextPos;
// ещё не знаем есть ли ещё разделител. поэтому пока считаем,
// что следующая итерация будет последней, а current() пока должен вернуть пустую строку
nextPos = stringLenPlus1 + 1;
currentLen = 0;
// начнем проверки
if( currentPos > stringLenPlus1 )
{
return false;
}
if( delimiterLen <= 0 )
{
if( currentIdx <= 1 )
{
currentLen = stringLenPlus1; // current() должен вернуть все оставшееся в строке
return true;
}
return false;
}
if( maxSubstrings )
{
if( currentIdx == maxSubstrings )
{
currentLen = stringLenPlus1; // current() должен вернуть все оставшееся в строке
return true;
}
else if( currentIdx > maxSubstrings )
{
return false;
}
}
// где наш разделитель?
pos = strscan(string, delimiterStr, currentPos, stringLenPlus1);
if( pos == 0 )
{
currentLen = stringLenPlus1; // current() должен вернуть все оставшееся в строке
return true;
}
// вот наш разделитель!
// установим правильную длину и правильную позицию для следующей итерации
currentLen = pos - currentPos;
nextPos = pos + delimiterLen;
return true;
}
public void new(str s, str delimiter, int _maxSubstrings = 0)
{
this.init(s, delimiter, _maxSubstrings);
}
// устанавливает индексы в начальное состояние
// никак не запоминает уже найденные позиции подстрок
public void reset()
{
currentIdx = 0;
currentPos = 0;
currentLen = 0;
nextPos = 1;
}
public str toString()
{
// поскольку этот метод может вызваться в отладчике еще до инициализации,
// то в этом методе нельзя использовать методы класса и нельзя бросать исключение
// и ни в коем случае не бросаем исключение на неинициализированные значения
str ret;
if( currentIdx )
{
if( currentPos <= stringLenPlus1 )
{
ret = strfmt('{%1}', this.current());
}
else
{
ret = '{after}';
}
}
else
{
ret = '{before}';
}
return ret;
}
public static server StrSplitEnumerator construct(str s, str delimiter, int maxSubstrings = 0)
{
return new StrSplitEnumerator(s, delimiter, maxSubstrings);
}
public static ClassDescription description()
{
return "An enumerator to traverse a splitted string chunks.";
}
}