27
27
import java .nio .charset .CoderResult ;
28
28
import java .nio .charset .CodingErrorAction ;
29
29
import java .util .Arrays ;
30
+ import java .util .Objects ;
30
31
import java .util .regex .Pattern ;
31
32
32
33
import rx .Observable ;
37
38
import rx .functions .Func2 ;
38
39
39
40
public class StringObservable {
41
+ /**
42
+ * Reads from the bytes from a source {@link InputStream} and outputs {@link Observable} of
43
+ * {@link byte[]}s
44
+ *
45
+ * @param i
46
+ * Source {@link InputStream}
47
+ * @return
48
+ */
40
49
public static Observable <byte []> from (final InputStream i ) {
41
50
return from (i , 8 * 1024 );
42
51
}
43
52
53
+ /**
54
+ * Reads from the bytes from a source {@link InputStream} and outputs {@link Observable} of
55
+ * {@link byte[]}s
56
+ *
57
+ * @param i
58
+ * Source {@link InputStream}
59
+ * @param size
60
+ * internal buffer size
61
+ * @return
62
+ */
44
63
public static Observable <byte []> from (final InputStream i , final int size ) {
45
64
return Observable .create (new OnSubscribe <byte []>() {
46
65
@ Override
@@ -65,10 +84,28 @@ public void call(Subscriber<? super byte[]> o) {
65
84
});
66
85
}
67
86
87
+ /**
88
+ * Reads from the characters from a source {@link Reader} and outputs {@link Observable} of
89
+ * {@link String}s
90
+ *
91
+ * @param i
92
+ * Source {@link Reader}
93
+ * @return
94
+ */
68
95
public static Observable <String > from (final Reader i ) {
69
96
return from (i , 8 * 1024 );
70
97
}
71
98
99
+ /**
100
+ * Reads from the characters from a source {@link Reader} and outputs {@link Observable} of
101
+ * {@link String}s
102
+ *
103
+ * @param i
104
+ * Source {@link Reader}
105
+ * @param size
106
+ * internal buffer size
107
+ * @return
108
+ */
72
109
public static Observable <String > from (final Reader i , final int size ) {
73
110
return Observable .create (new OnSubscribe <String >() {
74
111
@ Override
@@ -80,7 +117,7 @@ public void call(Subscriber<? super String> o) {
80
117
int n = 0 ;
81
118
n = i .read (buffer );
82
119
while (n != -1 && !o .isUnsubscribed ()) {
83
- o .onNext (new String (buffer ));
120
+ o .onNext (new String (buffer , 0 , n ));
84
121
n = i .read (buffer );
85
122
}
86
123
} catch (IOException e ) {
@@ -119,7 +156,7 @@ public static Observable<String> decode(Observable<byte[]> src, Charset charset)
119
156
120
157
/**
121
158
* Decodes a stream the multibyte chunks into a stream of strings that works on infinite streams
122
- * and where handles when a multibyte character spans two chunks.
159
+ * and where it handles when a multibyte character spans two chunks.
123
160
* This method allows for more control over how malformed and unmappable characters are handled.
124
161
*
125
162
* @param src
@@ -151,6 +188,9 @@ public void onNext(byte[] bytes) {
151
188
}
152
189
153
190
public boolean process (byte [] next , ByteBuffer last , boolean endOfInput ) {
191
+ if (o .isUnsubscribed ())
192
+ return false ;
193
+
154
194
ByteBuffer bb ;
155
195
if (last != null ) {
156
196
if (next != null ) {
@@ -270,8 +310,10 @@ public String call(String a, String b) {
270
310
/**
271
311
* Rechunks the strings based on a regex pattern and works on infinite stream.
272
312
*
273
- * resplit(["boo:an", "d:foo"], ":") --> ["boo", "and", "foo"]
274
- * resplit(["boo:an", "d:foo"], "o") --> ["b", "", ":and:f", "", ""]
313
+ * <pre>
314
+ * split(["boo:an", "d:foo"], ":") --> ["boo", "and", "foo"]
315
+ * split(["boo:an", "d:foo"], "o") --> ["b", "", ":and:f", "", ""]
316
+ * </pre>
275
317
*
276
318
* See {@link Pattern}
277
319
*
@@ -399,4 +441,56 @@ public void onNext(Object t) {
399
441
}
400
442
});
401
443
}
444
+
445
+ public final static class Line {
446
+ private final int number ;
447
+ private final String text ;
448
+
449
+ public Line (int number , String text ) {
450
+ this .number = number ;
451
+ this .text = text ;
452
+ }
453
+
454
+ public int getNumber () {
455
+ return number ;
456
+ }
457
+
458
+ public String getText () {
459
+ return text ;
460
+ }
461
+
462
+ @ Override
463
+ public int hashCode () {
464
+ return Objects .hash (number , text );
465
+ }
466
+
467
+ @ Override
468
+ public boolean equals (Object obj ) {
469
+ if (!(obj instanceof Line ))
470
+ return false ;
471
+ return Objects .equals (number , ((Line ) obj ).number ) && Objects .equals (text , ((Line ) obj ).text );
472
+ }
473
+
474
+ @ Override
475
+ public String toString () {
476
+ return number + ":" + text ;
477
+ }
478
+ }
479
+
480
+ /**
481
+ * Splits the {@link Observable} of Strings by lines and numbers them (zero based index)
482
+ *
483
+ * @param source
484
+ * @return
485
+ */
486
+ public static Observable <Line > byLine (Observable <String > source ) {
487
+ return split (source , System .getProperty ("line.separator" )).map (new Func1 <String , Line >() {
488
+ int lineNumber = 0 ;
489
+
490
+ @ Override
491
+ public Line call (String text ) {
492
+ return new Line (lineNumber ++, text );
493
+ }
494
+ });
495
+ }
402
496
}
0 commit comments