diff --git a/core-java-modules/core-java-string-operations-2/README.md b/core-java-modules/core-java-string-operations-2/README.md
index 6e88eda122..8687ac19ba 100644
--- a/core-java-modules/core-java-string-operations-2/README.md
+++ b/core-java-modules/core-java-string-operations-2/README.md
@@ -8,5 +8,6 @@ This module contains articles about string operations.
- [String Initialization in Java](https://www.baeldung.com/java-string-initialization)
- [String toLowerCase and toUpperCase Methods in Java](https://www.baeldung.com/java-string-convert-case)
- [Java String equalsIgnoreCase()](https://www.baeldung.com/java-string-equalsignorecase)
-- [How to avoid String contains() Case Insensitive in Java](https://www.baeldung.com/how-to-avoid-string-contains-case-insensitive-in-java)
+- [Case-Insensitive String Matching in Java](https://www.baeldung.com/java-case-insensitive-string-matching)
+- [L-Trim and R-Trim in Java](https://www.baeldung.com/l-trim-and-r-trim-in-java)
- More articles: [[<-- prev]](../core-java-string-operations)
diff --git a/core-java-modules/core-java-string-operations-2/pom.xml b/core-java-modules/core-java-string-operations-2/pom.xml
index b882e499b2..178edd55bc 100644
--- a/core-java-modules/core-java-string-operations-2/pom.xml
+++ b/core-java-modules/core-java-string-operations-2/pom.xml
@@ -109,7 +109,7 @@
3.6.1
2.0.0.Final
3.8.1
- 27.0.1-jre
+ 28.2-jre
6.0.2.Final
3.0.0
2.2.6
diff --git a/core-java-modules/core-java-string-operations-2/src/main/java/com/baeldung/trim/LTrimRTrim.java b/core-java-modules/core-java-string-operations-2/src/main/java/com/baeldung/trim/LTrimRTrim.java
new file mode 100644
index 0000000000..b300c783e1
--- /dev/null
+++ b/core-java-modules/core-java-string-operations-2/src/main/java/com/baeldung/trim/LTrimRTrim.java
@@ -0,0 +1,124 @@
+package com.baeldung.trim;
+
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang3.StringUtils;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+
+import com.google.common.base.CharMatcher;
+
+/**
+ * Based on https://github.com/tedyoung/indexof-contains-benchmark
+ */
+@Fork(5)
+@State(Scope.Benchmark)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+public class LTrimRTrim {
+
+ private String src;
+ private static String ltrimResult;
+ private static String rtrimResult;
+ private static Pattern LTRIM = Pattern.compile("^\\s+");
+ private static Pattern RTRIM = Pattern.compile("\\s+$");
+
+ public static void main(String[] args) throws Exception {
+ org.openjdk.jmh.Main.main(args);
+ }
+
+ @Setup
+ public void setup() {
+ src = " White spaces left and right ";
+ ltrimResult = "White spaces left and right ";
+ rtrimResult = " White spaces left and right";
+ }
+
+ public static String whileLtrim(String s) {
+ int i = 0;
+ while (i < s.length() && Character.isWhitespace(s.charAt(i))) {
+ i++;
+ }
+ return s.substring(i);
+ }
+
+ public static String whileRtrim(String s) {
+ int i = s.length() - 1;
+ while (i >= 0 && Character.isWhitespace(s.charAt(i))) {
+ i--;
+ }
+ return s.substring(0, i + 1);
+ }
+
+ private static boolean checkStrings(String ltrim, String rtrim) {
+ boolean result = false;
+
+ if (ltrimResult.equalsIgnoreCase(ltrim) && rtrimResult.equalsIgnoreCase(rtrim))
+ result = true;
+
+ return result;
+ }
+
+ // Going through the String detecting Whitespaces
+ @Benchmark
+ public boolean whileCharacters() {
+ String ltrim = whileLtrim(src);
+ String rtrim = whileRtrim(src);
+
+ return checkStrings(ltrim, rtrim);
+ }
+
+ // replaceAll() and Regular Expressions
+ @Benchmark
+ public boolean replaceAllRegularExpression() {
+ String ltrim = src.replaceAll("^\\s+", "");
+ String rtrim = src.replaceAll("\\s+$", "");
+
+ return checkStrings(ltrim, rtrim);
+ }
+
+ public static String patternLtrim(String s) {
+ return LTRIM.matcher(s)
+ .replaceAll("");
+ }
+
+ public static String patternRtrim(String s) {
+ return RTRIM.matcher(s)
+ .replaceAll("");
+ }
+
+ // Pattern matches() with replaceAll
+ @Benchmark
+ public boolean patternMatchesLTtrimRTrim() {
+ String ltrim = patternLtrim(src);
+ String rtrim = patternRtrim(src);
+
+ return checkStrings(ltrim, rtrim);
+ }
+
+ // Guava CharMatcher trimLeadingFrom / trimTrailingFrom
+ @Benchmark
+ public boolean guavaCharMatcher() {
+ String ltrim = CharMatcher.whitespace().trimLeadingFrom(src);
+ String rtrim = CharMatcher.whitespace().trimTrailingFrom(src);
+
+ return checkStrings(ltrim, rtrim);
+ }
+
+ // Apache Commons StringUtils containsIgnoreCase
+ @Benchmark
+ public boolean apacheCommonsStringUtils() {
+ String ltrim = StringUtils.stripStart(src, null);
+ String rtrim = StringUtils.stripEnd(src, null);
+
+ return checkStrings(ltrim, rtrim);
+ }
+
+}
diff --git a/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/trim/LTrimRTrimUnitTest.java b/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/trim/LTrimRTrimUnitTest.java
new file mode 100644
index 0000000000..78bf01e540
--- /dev/null
+++ b/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/trim/LTrimRTrimUnitTest.java
@@ -0,0 +1,78 @@
+package com.baeldung.trim;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.google.common.base.CharMatcher;
+
+import java.util.regex.Pattern;
+
+/**
+ * BAEL-3755: LTrim and RTrim examples.
+ */
+public class LTrimRTrimUnitTest {
+
+ private String src = " White spaces left and right ";
+ private final static String ltrimResult = "White spaces left and right ";
+ private final static String rtrimResult = " White spaces left and right";
+
+ @Test
+ public void givenString_whenCallingWhileCharacters_thenReturnsTrue() {
+ String ltrim = LTrimRTrim.whileLtrim(src);
+ String rtrim = LTrimRTrim.whileRtrim(src);
+
+ // Compare the Strings obtained and the expected
+ Assert.assertTrue(ltrimResult.equalsIgnoreCase(ltrim));
+
+ Assert.assertTrue(rtrimResult.equalsIgnoreCase(rtrim));
+ }
+
+ @Test
+ public void givenString_whenCallingContainsWithReplaceAll_shouldReturnTrue() {
+ // Use replaceAll with Regular Expressions
+ String ltrim = src.replaceAll("^\\s+", "");
+ String rtrim = src.replaceAll("\\s+$", "");
+
+ // Compare the Strings obtained and the expected
+ Assert.assertTrue(ltrimResult.equalsIgnoreCase(ltrim));
+
+ Assert.assertTrue(rtrimResult.equalsIgnoreCase(rtrim));
+ }
+
+ @Test
+ public void givenString_whenCallingPaternCompileMatcherReplaceAll_thenReturnsTrue() {
+ // Use Pattern Compile Matcher and Find to avoid case insensitive issues
+ String ltrim = LTrimRTrim.patternLtrim(src);
+ String rtrim = LTrimRTrim.patternRtrim(src);
+
+ // Compare the Strings obtained and the expected
+ Assert.assertTrue(ltrimResult.equalsIgnoreCase(ltrim));
+
+ Assert.assertTrue(rtrimResult.equalsIgnoreCase(rtrim));
+ }
+
+ @Test
+ public void givenString_whenCallingGuavaCharMatcher_thenReturnsTrue() {
+ // Use StringUtils containsIgnoreCase to avoid case insensitive issues
+ String ltrim = CharMatcher.whitespace().trimLeadingFrom(src);;
+ String rtrim = CharMatcher.whitespace().trimTrailingFrom(src);
+
+ // Compare the Strings obtained and the expected
+ Assert.assertTrue(ltrimResult.equalsIgnoreCase(ltrim));
+
+ Assert.assertTrue(rtrimResult.equalsIgnoreCase(rtrim));
+ }
+
+ @Test
+ public void givenString_whenCallingStringUtilsStripStartEnd_thenReturnsTrue() {
+ // Use StringUtils containsIgnoreCase to avoid case insensitive issues
+ String ltrim = StringUtils.stripStart(src, null);
+ String rtrim = StringUtils.stripEnd(src, null);
+
+ // Compare the Strings obtained and the expected
+ Assert.assertTrue(ltrimResult.equalsIgnoreCase(ltrim));
+ Assert.assertTrue(rtrimResult.equalsIgnoreCase(rtrim));
+ }
+
+}