001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.maven.doxia.util;
020
021/**
022 * Utility methods for string operations.
023 * This class provides methods that were previously supplied by Apache Commons Lang3.
024 *
025 * @since 2.1.0
026 */
027public class DoxiaStringUtils {
028
029    private DoxiaStringUtils() {
030        // utility class
031    }
032
033    /**
034     * Repeats a string a certain number of times.
035     *
036     * @param str the string to repeat
037     * @param repeat number of times to repeat
038     * @return the repeated string
039     */
040    public static String repeat(String str, int repeat) {
041        if (str == null) {
042            return null;
043        }
044        if (repeat <= 0) {
045            return "";
046        }
047        // Check for potential overflow
048        int len = str.length();
049        if (len > 0 && repeat > Integer.MAX_VALUE / len) {
050            throw new IllegalArgumentException("Resulting string would be too long");
051        }
052        StringBuilder sb = new StringBuilder(len * repeat);
053        for (int i = 0; i < repeat; i++) {
054            sb.append(str);
055        }
056        return sb.toString();
057    }
058
059    /**
060     * Replaces all occurrences of a string within another string.
061     *
062     * @param text the text to search and replace in
063     * @param searchString the string to search for
064     * @param replacement the string to replace with
065     * @return the text with any replacements processed
066     */
067    public static String replace(String text, String searchString, String replacement) {
068        if (text == null || text.isEmpty() || searchString == null || searchString.isEmpty()) {
069            return text;
070        }
071        if (replacement == null) {
072            replacement = "";
073        }
074        return text.replace(searchString, replacement);
075    }
076
077    /**
078     * Checks if a string is not empty.
079     *
080     * @param str the string to check
081     * @return true if the string is not null and not empty
082     */
083    public static boolean isNotEmpty(String str) {
084        return str != null && !str.isEmpty();
085    }
086
087    /**
088     * Checks if a string is blank (null, empty, or whitespace only).
089     *
090     * @param str the string to check
091     * @return true if the string is null, empty, or whitespace only
092     */
093    public static boolean isBlank(String str) {
094        if (str == null || str.isEmpty()) {
095            return true;
096        }
097        for (int i = 0; i < str.length(); i++) {
098            if (!Character.isWhitespace(str.charAt(i))) {
099                return false;
100            }
101        }
102        return true;
103    }
104
105    /**
106     * Checks if all strings are blank.
107     *
108     * @param strs the strings to check
109     * @return true if all strings are blank
110     */
111    public static boolean isAllBlank(String... strs) {
112        if (strs == null || strs.length == 0) {
113            return true;
114        }
115        for (String str : strs) {
116            if (!isBlank(str)) {
117                return false;
118            }
119        }
120        return true;
121    }
122
123    /**
124     * Splits a string by specified delimiters.
125     *
126     * @param str the string to split
127     * @param separatorChars the characters to use as delimiters
128     * @return an array of parsed strings, empty array if null string input
129     */
130    public static String[] split(String str, String separatorChars) {
131        if (str == null) {
132            return new String[0];
133        }
134        if (str.isEmpty()) {
135            return new String[0];
136        }
137        if (separatorChars == null || separatorChars.isEmpty()) {
138            separatorChars = " \t\n\r\f";
139        }
140
141        java.util.List<String> result = new java.util.ArrayList<>();
142        int start = 0;
143        int len = str.length();
144
145        while (start < len) {
146            // Skip separators
147            while (start < len && separatorChars.indexOf(str.charAt(start)) >= 0) {
148                start++;
149            }
150            if (start >= len) {
151                break;
152            }
153            // Find end of token
154            int end = start;
155            while (end < len && separatorChars.indexOf(str.charAt(end)) < 0) {
156                end++;
157            }
158            result.add(str.substring(start, end));
159            start = end;
160        }
161
162        return result.toArray(new String[0]);
163    }
164
165    /**
166     * Removes a substring only if it is at the end of a source string.
167     *
168     * @param str the source string
169     * @param remove the string to remove
170     * @return the substring with the string removed if found
171     */
172    public static String removeEnd(String str, String remove) {
173        if (str == null || remove == null || str.isEmpty() || remove.isEmpty()) {
174            return str;
175        }
176        if (str.endsWith(remove)) {
177            return str.substring(0, str.length() - remove.length());
178        }
179        return str;
180    }
181
182    /**
183     * Strips any of a set of characters from the start of a string.
184     *
185     * @param str the string to remove characters from
186     * @param stripChars the characters to remove
187     * @return the stripped string
188     */
189    public static String stripStart(String str, String stripChars) {
190        if (str == null || str.isEmpty()) {
191            return str;
192        }
193        int start = 0;
194        int len = str.length();
195        if (stripChars == null) {
196            while (start < len && Character.isWhitespace(str.charAt(start))) {
197                start++;
198            }
199        } else {
200            while (start < len && stripChars.indexOf(str.charAt(start)) >= 0) {
201                start++;
202            }
203        }
204        return start > 0 ? str.substring(start) : str;
205    }
206
207    /**
208     * Counts how many times the substring appears in the larger string.
209     *
210     * @param str the string to check
211     * @param sub the substring to count
212     * @return the number of occurrences, 0 if either string is null
213     */
214    public static int countMatches(String str, String sub) {
215        if (str == null || str.isEmpty() || sub == null || sub.isEmpty()) {
216            return 0;
217        }
218        int count = 0;
219        int idx = 0;
220        while ((idx = str.indexOf(sub, idx)) != -1) {
221            count++;
222            idx += sub.length();
223        }
224        return count;
225    }
226}