Skip to content

Commit c9b2222

Browse files
authored
Add case sensitivity support to ExprIndicesOf & Cleanup (#7997)
1 parent 4a97f91 commit c9b2222

File tree

4 files changed

+118
-46
lines changed

4 files changed

+118
-46
lines changed

src/main/java/ch/njol/skript/expressions/ExprIndicesOf.java renamed to src/main/java/ch/njol/skript/expressions/ExprIndicesOfValue.java

Lines changed: 65 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
package ch.njol.skript.expressions;
22

3+
import ch.njol.skript.SkriptConfig;
4+
import ch.njol.skript.doc.Description;
5+
import ch.njol.skript.doc.Example;
6+
import ch.njol.skript.doc.Name;
7+
import ch.njol.skript.doc.Since;
38
import ch.njol.skript.lang.*;
49
import ch.njol.skript.lang.simplification.SimplifiedLiteral;
510
import ch.njol.skript.util.LiteralUtils;
11+
import ch.njol.util.StringUtils;
612
import org.bukkit.event.Event;
713
import org.jetbrains.annotations.Nullable;
814

915
import ch.njol.skript.Skript;
10-
import ch.njol.skript.doc.Description;
11-
import ch.njol.skript.doc.Examples;
12-
import ch.njol.skript.doc.Name;
13-
import ch.njol.skript.doc.Since;
1416
import ch.njol.skript.lang.SkriptParser.ParseResult;
1517
import ch.njol.skript.lang.util.SimpleExpression;
1618
import ch.njol.util.Kleenean;
1719

1820
import java.lang.reflect.Array;
1921
import java.util.*;
2022

21-
@Name("Indices Of")
23+
@Name("Indices of Value")
2224
@Description({
2325
"Get the first, last or all positions of a character (or text) in another text using "
2426
+ "'positions of %text% in %text%'. Nothing is returned when the value does not occur in the text. "
@@ -30,45 +32,51 @@
3032
+ "and will return the string indices of the given value. "
3133
+ "Positions can be used with any list and will return "
3234
+ "the numerical position of the value in the list, counting up from 1. "
33-
+ "As well, nothing is returned if the value is not found in the list."
34-
})
35-
@Examples({
36-
"set {_first} to the first position of \"@\" in the text argument",
37-
"if {_s} contains \"abc\":",
38-
"\tset {_s} to the first (position of \"abc\" in {_s} + 3) characters of {_s}",
39-
"\t# removes everything after the first \"abc\" from {_s}",
40-
"",
41-
"set {_list::*} to 1, 2, 3, 1, 2, 3",
42-
"set {_indices::*} to indices of the value 1 in {_list::*}",
43-
"# {_indices::*} is now \"1\" and \"4\"",
44-
"",
45-
"set {_indices::*} to all indices of the value 2 in {_list::*}",
46-
"# {_indices::*} is now \"2\" and \"5\"",
35+
+ "Additionally, nothing is returned if the value is not found in the list.",
4736
"",
48-
"set {_positions::*} to all positions of the value 3 in {_list::*}",
49-
"# {_positions::*} is now 3 and 6",
50-
"",
51-
"set {_otherlist::bar} to 100",
52-
"set {_otherlist::hello} to \"hi\"",
53-
"set {_otherlist::burb} to 100",
54-
"set {_otherlist::tud} to \"hi\"",
55-
"set {_otherlist::foo} to 100",
56-
"",
57-
"set {_indices::*} to the first index of the value 100 in {_otherlist::*}",
58-
"# {_indices::*} is now \"bar\"",
59-
"set {_indices::*} to the last index of the value 100 in {_otherlist::*}",
60-
"# {_indices::*} is now \"foo\"",
61-
"",
62-
"set {_positions::*} to all positions of the value 100 in {_otherlist::*}",
63-
"# {_positions::*} is now 1, 3 and 5",
64-
"set {_positions::*} to all positions of the value \"hi\" in {_otherlist::*}",
65-
"# {_positions::*} is now 2 and 4"
37+
"Whether string comparison is case-sensitive or not can be configured in Skript's config file.",
6638
})
39+
@Example("""
40+
set {_first} to the first position of "@" in the text argument
41+
if {_s} contains "abc":
42+
set {_s} to the first (position of "abc" in {_s} + 3) characters of {_s}
43+
# removes everything after the first "abc" from {_s}
44+
""")
45+
@Example("""
46+
set {_list::*} to 1, 2, 3, 1, 2, 3
47+
set {_indices::*} to indices of the value 1 in {_list::*}
48+
# {_indices::*} is now "1" and "4"
49+
50+
set {_indices::*} to all indices of the value 2 in {_list::*}
51+
# {_indices::*} is now "2" and "5"
52+
53+
set {_positions::*} to all positions of the value 3 in {_list::*}
54+
# {_positions::*} is now 3 and 6
55+
""")
56+
@Example("""
57+
set {_otherlist::bar} to 100
58+
set {_otherlist::hello} to "hi"
59+
set {_otherlist::burb} to 100
60+
set {_otherlist::tud} to "hi"
61+
set {_otherlist::foo} to 100
62+
63+
set {_indices::*} to the first index of the value 100 in {_otherlist::*}
64+
# {_indices::*} is now "bar"
65+
66+
set {_indices::*} to the last index of the value 100 in {_otherlist::*}
67+
# {_indices::*} is now "foo"
68+
69+
set {_positions::*} to all positions of the value 100 in {_otherlist::*}
70+
# {_positions::*} is now 1, 3 and 5
71+
72+
set {_positions::*} to all positions of the value "hi" in {_otherlist::*}
73+
# {_positions::*} is now 2 and 4
74+
""")
6775
@Since("2.1, 2.12 (indices, positions of list)")
68-
public class ExprIndicesOf extends SimpleExpression<Object> {
76+
public class ExprIndicesOfValue extends SimpleExpression<Object> {
6977

7078
static {
71-
Skript.registerExpression(ExprIndicesOf.class, Object.class, ExpressionType.COMBINED,
79+
Skript.registerExpression(ExprIndicesOfValue.class, Object.class, ExpressionType.COMBINED,
7280
"[the] [1:first|2:last|3:all] (position[mult:s]|mult:indices|index[mult:es]) of [[the] value] %string% in %string%",
7381
"[the] [1:first|2:last|3:all] position[mult:s] of [[the] value] %object% in %~objects%",
7482
"[the] [1:first|2:last|3:all] (mult:indices|index[mult:es]) of [[the] value] %object% in %~objects%"
@@ -129,27 +137,31 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
129137
}
130138

131139
private Long[] getStringPositions(String haystack, String needle) {
140+
boolean caseSensitive = SkriptConfig.caseSensitive.value();
141+
132142
List<Long> positions = new ArrayList<>();
133-
long position = haystack.indexOf(needle);
143+
long position = StringUtils.indexOf(haystack, needle, caseSensitive);
134144

135145
if (position == -1)
136146
return new Long[0];
137147

138148
if (indexType == IndexType.ALL) {
139149
while (position != -1) {
140150
positions.add(position + 1);
141-
position = haystack.indexOf(needle, (int) position + 1);
151+
position = StringUtils.indexOf(haystack, needle, (int) position + 1, caseSensitive);
142152
}
143-
return positions.toArray(new Long[0]);
153+
return positions.toArray(Long[]::new);
144154
}
145155

146156
if (indexType == IndexType.LAST)
147-
position = haystack.lastIndexOf(needle);
157+
position = StringUtils.lastIndexOf(haystack, needle, caseSensitive);
148158

149159
return new Long[]{position + 1};
150160
}
151161

152162
private Long[] getListPositions(Expression<?> list, Object value, Event event) {
163+
boolean caseSensitive = SkriptConfig.caseSensitive.value();
164+
153165
Iterator<?> iterator = list.iterator(event);
154166
if (iterator == null)
155167
return new Long[0];
@@ -160,7 +172,7 @@ private Long[] getListPositions(Expression<?> list, Object value, Event event) {
160172
while (iterator.hasNext()) {
161173
position++;
162174

163-
if (!iterator.next().equals(value))
175+
if (!equals(iterator.next(), value, caseSensitive))
164176
continue;
165177

166178
if (indexType == IndexType.FIRST)
@@ -176,6 +188,8 @@ private Long[] getListPositions(Expression<?> list, Object value, Event event) {
176188
}
177189

178190
private String[] getIndices(KeyProviderExpression<?> expression, Object value, Event event) {
191+
boolean caseSensitive = SkriptConfig.caseSensitive.value();
192+
179193
Iterator<? extends KeyedValue<?>> iterator = expression.keyedIterator(event);
180194
if (iterator == null)
181195
return new String[0];
@@ -185,7 +199,7 @@ private String[] getIndices(KeyProviderExpression<?> expression, Object value, E
185199
while (iterator.hasNext()) {
186200
var keyedValue = iterator.next();
187201

188-
if (!keyedValue.value().equals(value))
202+
if (!equals(keyedValue.value(), value, caseSensitive))
189203
continue;
190204
if (indexType == IndexType.FIRST)
191205
return new String[]{keyedValue.key()};
@@ -202,6 +216,12 @@ private String[] getIndices(KeyProviderExpression<?> expression, Object value, E
202216
return indices.toArray(String[]::new);
203217
}
204218

219+
private boolean equals(Object key, Object value, boolean caseSensitive) {
220+
if (key instanceof String keyString && value instanceof String valueString)
221+
return StringUtils.equals(keyString, valueString, caseSensitive);
222+
return key.equals(value);
223+
}
224+
205225
@Override
206226
public boolean isSingle() {
207227
return indexType == IndexType.FIRST || indexType == IndexType.LAST;

src/main/java/ch/njol/util/StringUtils.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,58 @@ private static int indexOf(final char[] s, final int start, final char... cs) {
174174
return -1;
175175
}
176176

177+
/**
178+
* Returns the index of the first occurrence of the needle in the haystack.
179+
* @param haystack the string to search in
180+
* @param needle the string to search for
181+
* @param caseSensitive whether the search should be case-sensitive
182+
* @return the index of the first occurrence of the needle in the haystack, or -1 if not found
183+
*/
184+
public static int indexOf(String haystack, String needle, boolean caseSensitive) {
185+
if (caseSensitive) {
186+
haystack = haystack.toLowerCase(Locale.ENGLISH);
187+
needle = needle.toLowerCase(Locale.ENGLISH);
188+
}
189+
190+
return haystack.indexOf(needle);
191+
}
192+
193+
/**
194+
* Returns the index of the first occurrence of the needle in the haystack, starting from the specified index.
195+
* @param haystack the string to search in
196+
* @param needle the string to search for
197+
* @param fromIndex the index to start searching from
198+
* @param caseSensitive whether the search should be case-sensitive
199+
* @return the index of the first occurrence of the needle in the haystack, or -1 if not found
200+
*/
201+
public static int indexOf(String haystack, String needle, int fromIndex, boolean caseSensitive) {
202+
if (fromIndex < 0 || fromIndex >= haystack.length())
203+
return -1;
204+
205+
if (caseSensitive) {
206+
haystack = haystack.toLowerCase(Locale.ENGLISH);
207+
needle = needle.toLowerCase(Locale.ENGLISH);
208+
}
209+
210+
return haystack.indexOf(needle, fromIndex);
211+
}
212+
213+
/**
214+
* Returns the index of the last occurrence of the needle in the haystack.
215+
* @param haystack the string to search in
216+
* @param needle the string to search for
217+
* @param caseSensitive whether the search should be case-sensitive
218+
* @return the index of the last occurrence of the needle in the haystack, or -1 if not found
219+
*/
220+
public static int lastIndexOf(String haystack, String needle, boolean caseSensitive) {
221+
if (caseSensitive) {
222+
haystack = haystack.toLowerCase(Locale.ENGLISH);
223+
needle = needle.toLowerCase(Locale.ENGLISH);
224+
}
225+
226+
return haystack.lastIndexOf(needle);
227+
}
228+
177229
/**
178230
* Shorthand for <tt>{@link #numberAt(CharSequence, int, boolean) numberAt}(s, index, true)</tt>
179231
*

src/main/resources/config.sk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ maximum target block distance: 100
150150

151151
case sensitive: false
152152
# Whether Skript's functions should be case sensitive or not.
153-
# This e.g. applies to the effect 'replace' and the conditions 'contains' and 'is/is not'.
153+
# This e.g. applies to the effect 'replace', expression 'indices of value' and the conditions 'contains' and 'is/is not'.
154154
# Variable names are case-insensitive irrespective of this setting.
155155

156156
case-insensitive variables: true

src/test/skript/tests/syntaxes/expressions/ExprIndicesOf.sk renamed to src/test/skript/tests/syntaxes/expressions/ExprIndicesOfValue.sk

File renamed without changes.

0 commit comments

Comments
 (0)