1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.opencsv.bean;
17
18 import com.opencsv.ICSVParser;
19 import com.opencsv.exceptions.CsvBadConverterException;
20 import org.apache.commons.lang3.Range;
21 import org.apache.commons.lang3.StringUtils;
22
23 import java.util.*;
24
25
26
27
28
29
30
31 public class PositionToBeanField<T> extends AbstractFieldMapEntry<String, Integer, T> implements Iterable<FieldMapByPositionEntry<T>> {
32
33
34
35
36
37
38
39 private final String initializer;
40
41
42 private final List<Range<Integer>> ranges;
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public PositionToBeanField(final String rangeDefinition, int maxIndex, final BeanField<T, Integer> field, Locale errorLocale) {
57 super(field, errorLocale);
58 initializer = rangeDefinition;
59 ranges = new LinkedList<>();
60
61
62 if(StringUtils.isBlank(rangeDefinition)) {
63 throw new CsvBadConverterException(
64 BeanFieldJoin.class,
65 String.format(
66 ResourceBundle.getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, this.errorLocale)
67 .getString("invalid.range.definition"),
68 rangeDefinition));
69 }
70
71 final String[] partialRangeDefinitions = rangeDefinition.split(",");
72 try {
73 for(String r : partialRangeDefinitions) {
74 if(StringUtils.isNotEmpty(r)) {
75 Range<Integer> range;
76
77
78 if(r.contains("-")) {
79 final String[] endpoints = r.split("-", 2);
80 final Integer min = StringUtils.isEmpty(endpoints[0]) ? Integer.valueOf(0) : Integer.valueOf(endpoints[0].trim());
81 Integer max = maxIndex;
82 if(endpoints.length == 2 && StringUtils.isNotEmpty(endpoints[1])) {
83 max = Integer.valueOf(endpoints[1].trim());
84 }
85 if(max >= maxIndex) {
86 if(min >= maxIndex) {
87 max = min;
88 }
89 else {
90 max = maxIndex;
91 }
92 }
93 range = Range.between(min, max);
94 }
95 else {
96 range = Range.is(Integer.valueOf(r));
97 }
98
99
100
101 final ListIterator<Range<Integer>> it = ranges.listIterator();
102 boolean completelyContained = false;
103 while(it.hasNext() && ! completelyContained) {
104 final Range<Integer> next = it.next();
105 if(next.containsRange(range)) {
106 completelyContained = true;
107 }
108 else {
109 if(next.isOverlappedBy(range)) {
110 range = Range.between(
111 Math.min(next.getMinimum(), range.getMinimum()),
112 Math.max(next.getMaximum(), range.getMaximum()));
113 it.remove();
114 }
115 else if(next.getMaximum()+1 == range.getMinimum()) {
116 range = Range.between(next.getMinimum(), range.getMaximum());
117 }
118 else if(range.getMaximum()+1 == next.getMinimum()) {
119 range = Range.between(range.getMinimum(), next.getMaximum());
120 }
121 }
122 }
123 if(!completelyContained) {
124 ranges.add(range);
125 }
126 }
127 }
128 }
129 catch(NumberFormatException e) {
130
131 final CsvBadConverterException csve = new CsvBadConverterException(
132 BeanFieldJoin.class,
133 String.format(
134 ResourceBundle.getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, this.errorLocale)
135 .getString("invalid.range.definition"),
136 rangeDefinition));
137 csve.initCause(e);
138 throw csve;
139 }
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153 public void attenuateRanges(int maxIndex) {
154 ListIterator<Range<Integer>> rangeIterator = ranges.listIterator();
155 while(rangeIterator.hasNext()) {
156 Range<Integer> r = rangeIterator.next();
157 if(r.getMaximum() > maxIndex) {
158 if(r.getMinimum() > maxIndex) {
159 rangeIterator.set(Range.is(r.getMinimum()));
160 }
161 else {
162 rangeIterator.set(Range.between(r.getMinimum(), maxIndex));
163 }
164 }
165 }
166 }
167
168 @Override
169 public boolean contains(Integer key) {
170 return ranges.stream().anyMatch(range -> range.contains(key));
171 }
172
173 @Override
174 public String getInitializer() {
175 return initializer;
176 }
177
178 @Override
179 public Iterator<FieldMapByPositionEntry<T>> iterator() {
180 return new PositionIterator();
181 }
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197 private class PositionIterator implements Iterator<FieldMapByPositionEntry<T>> {
198
199 private ListIterator<Range<Integer>> rangeIterator;
200 private Range<Integer> currentRange;
201 private int position;
202
203 PositionIterator() {
204 if(ranges.isEmpty()) {
205 position = -1;
206 }
207 else {
208 rangeIterator = ranges.listIterator();
209 currentRange = rangeIterator.next();
210 position = currentRange.getMinimum();
211 }
212 }
213
214 @Override
215 public boolean hasNext() {
216 return position != -1;
217 }
218
219 @Override
220 public FieldMapByPositionEntry<T> next() {
221
222
223 if(!hasNext()) {
224 throw new NoSuchElementException();
225 }
226
227
228 FieldMapByPositionEntry<T> entry = new FieldMapByPositionEntry<>(position, field);
229
230
231
232
233 if(position == currentRange.getMaximum()
234 || Integer.MAX_VALUE == currentRange.getMaximum()) {
235 if(!rangeIterator.hasNext()) {
236 position = -1;
237 }
238 else {
239 currentRange = rangeIterator.next();
240 position = currentRange.getMinimum();
241 }
242 }
243 else {
244 position++;
245 }
246 return entry;
247 }
248
249 @Override
250 public void remove() {
251 throw new UnsupportedOperationException();
252 }
253 }
254 }