diff --git a/src/main/java/org/cactoos/func/BiFuncSplitPreserve.java b/src/main/java/org/cactoos/func/BiFuncSplitPreserve.java new file mode 100644 index 000000000..cef50270b --- /dev/null +++ b/src/main/java/org/cactoos/func/BiFuncSplitPreserve.java @@ -0,0 +1,25 @@ +package org.cactoos.func; + +import org.cactoos.BiFunc; +import org.cactoos.list.ListOf; + +import java.util.Collection; + +public class BiFuncSplitPreserve implements BiFunc> { + @Override + public Collection apply(String str, String regex) throws Exception { + ListOf ret = new ListOf<>(); + int start = 0; + int pos = str.indexOf(regex); + while (pos >= start) { + ret.add(str.substring(start, pos)); + start = pos + regex.length(); + pos = str.indexOf(regex, start); + } + if (start < str.length()) + ret.add(str.substring(start)); + else if (start == str.length()) + ret.add(""); + return ret; + } +} diff --git a/src/main/java/org/cactoos/text/SplitPreserveAllTokens.java b/src/main/java/org/cactoos/text/SplitPreserveAllTokens.java new file mode 100644 index 000000000..bd60eeddb --- /dev/null +++ b/src/main/java/org/cactoos/text/SplitPreserveAllTokens.java @@ -0,0 +1,181 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017-2024 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.text; + +import org.cactoos.Text; +import org.cactoos.func.BiFuncSplitPreserve; +import org.cactoos.iterable.IterableEnvelope; +import org.cactoos.iterable.IterableOf; +import org.cactoos.iterable.Mapped; +import org.cactoos.iterator.IteratorOf; + +/** + * Splits the Text into an array, including empty + * tokens created by adjacent separators. + * + * @see String#split(String) + * @see String#split(String, int) + * @since 0.9 + */ +public final class SplitPreserveAllTokens extends IterableEnvelope { + /** + * Ctor. + * + * @param text The text + * @see String#split(String) + */ + public SplitPreserveAllTokens(final CharSequence text) { + this(new TextOf(text), new TextOf(" ")); + } + + /** + * Ctor. + * + * @param text The text + * @see String#split(String) + */ + public SplitPreserveAllTokens(final Text text) { + this(text, new TextOf(" ")); + } + /** + * Ctor. + * + * @param text The text + * @param lmt The limit + * @see String#split(String, int) + */ + public SplitPreserveAllTokens(final CharSequence text, final int lmt) { + this(new TextOf(text), new TextOf(" "), lmt); + } + + /** + * Ctor. + * + * @param text The text + * @param lmt The limit + * @see String#split(String, int) + */ + public SplitPreserveAllTokens(final Text text, final int lmt) { + this(text, new TextOf(" "), lmt); + } + /** + * Ctor. + * + * @param text The text + * @param rgx The regex + * @see String#split(String) + */ + public SplitPreserveAllTokens(final CharSequence text, final CharSequence rgx) { + this(new TextOf(text), new TextOf(rgx)); + } + + /** + * Ctor. + * + * @param text The text + * @param rgx The regex + * @param lmt The limit + * @see String#split(String, int) + */ + public SplitPreserveAllTokens(final CharSequence text, final CharSequence rgx, final int lmt) { + this(new TextOf(text), new TextOf(rgx), lmt); + } + + /** + * Ctor. + * @param text The text + * @param rgx The regex + * @see String#split(String) + */ + public SplitPreserveAllTokens(final CharSequence text, final Text rgx) { + this(new TextOf(text), rgx); + } + + /** + * Ctor. + * @param text The text + * @param rgx The regex + * @param lmt The limit + * @see String#split(String, int) + */ + public SplitPreserveAllTokens(final CharSequence text, final Text rgx, final int lmt) { + this(new TextOf(text), rgx, lmt); + } + + /** + * Ctor. + * @param text The text + * @param rgx The regex + * @see String#split(String) + */ + public SplitPreserveAllTokens(final Text text, final CharSequence rgx) { + this(text, new TextOf(rgx)); + } + + /** + * Ctor. + * @param text The text + * @param rgx The regex + * @param lmt The limit + * @see String#split(String, int) + */ + public SplitPreserveAllTokens(final Text text, final CharSequence rgx, final int lmt) { + this(text, new TextOf(rgx), lmt); + } + + /** + * Ctor. + * @param text The text + * @param rgx The regex + * @see String#split(String) + */ + public SplitPreserveAllTokens(final Text text, final Text rgx) { + this(text, rgx, 0); + } + + /** + * Ctor. + * @param text The text + * @param rgx The regex + * @param lmt The limit + * @see String#split(String, int) + */ + public SplitPreserveAllTokens( + final Text text, final Text rgx, final int lmt + ) { + super( + new Mapped<>( + TextOf::new, + new IterableOf<>( + () -> new IteratorOf<>( + new BiFuncSplitPreserve() + .apply(text.toString(), + rgx.toString()) + .toArray(new String[0])) + ) + ) + ); + } + +} diff --git a/src/test/java/org/cactoos/text/SplitPreserveTest.java b/src/test/java/org/cactoos/text/SplitPreserveTest.java new file mode 100644 index 000000000..77c872c9f --- /dev/null +++ b/src/test/java/org/cactoos/text/SplitPreserveTest.java @@ -0,0 +1,90 @@ +package org.cactoos.text; + +import org.cactoos.Text; +import org.cactoos.iterable.IterableOf; +import org.hamcrest.Matchers; +import org.hamcrest.core.IsNot; +import org.junit.jupiter.api.Test; +import org.llorllale.cactoos.matchers.Assertion; + +import java.util.ArrayList; +import java.util.Iterator; + +public class SplitPreserveTest { + @Test + void checkingSplit() throws Exception { + String txt = " "; + ArrayList array = new ArrayList<>(); + array.add(new TextOf("")); + array.add(new TextOf("")); + array.add(new TextOf("")); + array.add(new TextOf("")); + new Assertion<>( + "Adjacent separators must create an empty element", + getLength(new Split(new TextOf(txt), new TextOf(" ")).iterator()), + IsNot.not(Matchers.equalTo(getLength(new IterableOf(array.iterator()).iterator()))) + ).affirm(); + + txt = " how "; + array = new ArrayList<>(); + array.add(new TextOf("")); + array.add(new TextOf("how")); + array.add(new TextOf("")); + + new Assertion<>( + "Adjacent separators must create an empty element", + getLength(new Split(new TextOf(txt), new TextOf(" ")).iterator()), + IsNot.not(Matchers.equalTo(getLength(new IterableOf(array.iterator()).iterator()))) + ).affirm(); + } + + int getLength(Iterator iter) { + int count = 0; + while (iter.hasNext()) { + iter.next(); + count++; + } + return count; + } + + @Test + void checkingSplitPreserveTokens() throws Exception { + String txt = " "; + ArrayList array = new ArrayList<>(); + array.add(new TextOf("")); + array.add(new TextOf("")); + array.add(new TextOf("")); + array.add(new TextOf("")); + + new Assertion<>( + "Adjacent separators must create an empty element", + getLength(new SplitPreserveAllTokens(new TextOf(txt), new TextOf(" ")).iterator()), + Matchers.equalTo(getLength(new IterableOf(array.iterator()).iterator())) + ).affirm(); + + txt = "lol\\ / dude"; + array = new ArrayList<>(); + array.add(new TextOf("lol\\")); + array.add(new TextOf("")); + array.add(new TextOf("/")); + array.add(new TextOf("dude")); + + new Assertion<>( + "Adjacent separators must create an empty element", + getLength(new SplitPreserveAllTokens(new TextOf(txt), new TextOf(" ")).iterator()), + Matchers.equalTo(getLength(new IterableOf(array.iterator()).iterator())) + ).affirm(); + + txt = " how "; + array = new ArrayList<>(); + array.add(new TextOf("")); + array.add(new TextOf("how")); + array.add(new TextOf("")); + + new Assertion<>( + "Adjacent separators must create an empty element", + getLength(new SplitPreserveAllTokens(new TextOf(txt), new TextOf(" ")).iterator()), + Matchers.equalTo(getLength(new IterableOf(array.iterator()).iterator())) + ).affirm(); + } +} \ No newline at end of file