001/*
002 * PlotSquared, a land and world management plugin for Minecraft.
003 * Copyright (C) IntellectualSites <https://intellectualsites.com>
004 * Copyright (C) IntellectualSites team and contributors
005 *
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
018 */
019package com.plotsquared.core.util;
020
021import org.checkerframework.checker.nullness.qual.NonNull;
022
023import java.util.ArrayList;
024import java.util.Arrays;
025import java.util.Collection;
026import java.util.Comparator;
027import java.util.List;
028import java.util.Set;
029import java.util.regex.Pattern;
030
031public class StringMan {
032
033    // Stolen from https://stackoverflow.com/a/366532/12620913 | Debug: https://regex101.com/r/DudJLb/1
034    private static final Pattern STRING_SPLIT_PATTERN = Pattern.compile("[^\\s\"]+|\"([^\"]*)\"");
035
036    public static int intersection(Set<String> options, String[] toCheck) {
037        int count = 0;
038        for (String check : toCheck) {
039            if (options.contains(check)) {
040                count++;
041            }
042        }
043        return count;
044    }
045
046    public static boolean isAlphanumericUnd(String str) {
047        for (int i = 0; i < str.length(); i++) {
048            char c = str.charAt(i);
049            if (c < 0x30 || (c >= 0x3a) && (c <= 0x40) || (c > 0x5a) && (c <= 0x60) || (c > 0x7a)) {
050                return false;
051            }
052        }
053        return true;
054    }
055
056    public static String join(Collection<?> collection, String delimiter) {
057        return join(collection.toArray(), delimiter);
058    }
059
060    public static String joinOrdered(Collection<?> collection, String delimiter) {
061        Object[] array = collection.toArray();
062        Arrays.sort(array, Comparator.comparingInt(Object::hashCode));
063        return join(array, delimiter);
064    }
065
066    public static int getLevenshteinDistance(String s, String t) {
067        int n = s.length();
068        int m = t.length();
069        if (n == 0) {
070            return m;
071        } else if (m == 0) {
072            return n;
073        }
074        if (n > m) {
075            String tmp = s;
076            s = t;
077            t = tmp;
078            n = m;
079            m = t.length();
080        }
081        int[] p = new int[n + 1];
082        int[] d = new int[n + 1];
083        int i;
084        for (i = 0; i <= n; i++) {
085            p[i] = i;
086        }
087        for (int j = 1; j <= m; j++) {
088            char t_j = t.charAt(j - 1);
089            d[0] = j;
090
091            for (i = 1; i <= n; i++) {
092                int cost = s.charAt(i - 1) == t_j ? 0 : 1;
093                d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
094            }
095            int[] _d = p;
096            p = d;
097            d = _d;
098        }
099        return p[n];
100    }
101
102    public static String join(Object[] array, String delimiter) {
103        StringBuilder result = new StringBuilder();
104        for (int i = 0, j = array.length; i < j; i++) {
105            if (i > 0) {
106                result.append(delimiter);
107            }
108            result.append(array[i]);
109        }
110        return result.toString();
111    }
112
113    public static boolean isEqualIgnoreCaseToAny(@NonNull String a, String... args) {
114        for (String arg : args) {
115            if (a.equalsIgnoreCase(arg)) {
116                return true;
117            }
118        }
119        return false;
120    }
121
122    public static boolean isEqual(String a, String b) {
123        if ((a == null && b != null) || (a != null && b == null)) {
124            return false;
125        } else if (a == null /* implies that b is null */) {
126            return false;
127        }
128        return a.equals(b);
129    }
130
131    public static String repeat(String s, int n) {
132        StringBuilder sb = new StringBuilder();
133        sb.append(String.valueOf(s).repeat(Math.max(0, n)));
134        return sb.toString();
135    }
136
137    /**
138     * @param message an input string
139     * @return a list of strings
140     * @since 6.4.0
141     *
142     *         <table border="1">
143     *         <caption>Converts multiple quoted and single strings into a list of strings</caption>
144     *         <thead>
145     *           <tr>
146     *             <th>Input</th>
147     *             <th>Output</th>
148     *           </tr>
149     *         </thead>
150     *         <tbody>
151     *           <tr>
152     *             <td>title "sub title"</td>
153     *             <td>["title", "sub title"]</td>
154     *           </tr>
155     *           <tr>
156     *             <td>"a title" subtitle</td>
157     *             <td>["a title", "subtitle"]</td>
158     *           </tr>
159     *           <tr>
160     *             <td>"title" "subtitle"</td>
161     *             <td>["title", "subtitle"]</td>
162     *           </tr>
163     *           <tr>
164     *             <td>"PlotSquared is going well" the authors "and many contributors"</td>
165     *             <td>["PlotSquared is going well", "the", "authors", "and many contributors"]</td>
166     *           </tr>
167     *         </tbody>
168     *         </table>
169     */
170    public static @NonNull List<String> splitMessage(@NonNull String message) {
171        var matcher = StringMan.STRING_SPLIT_PATTERN.matcher(message);
172        List<String> splitMessages = new ArrayList<>();
173        while (matcher.find()) {
174            splitMessages.add(matcher.group(matcher.groupCount() - 1).replaceAll("\"", ""));
175        }
176        return splitMessages;
177    }
178
179}