Skip to content

Commit 030a90f

Browse files
committed
Improve Alphabetical implementation, tests and documentation
1 parent 49f9e1a commit 030a90f

File tree

2 files changed

+85
-20
lines changed

2 files changed

+85
-20
lines changed
Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,58 @@
11
package com.thealgorithms.strings;
22

3+
import java.util.Locale;
4+
35
/**
4-
* Utility class for checking if a string's characters are in alphabetical order.
6+
* Utility class for checking whether a string's characters are in non-decreasing
7+
* lexicographical order based on Unicode code points (case-insensitive).
8+
* <p>
9+
* This does NOT implement language-aware alphabetical ordering (collation rules).
10+
* It simply compares lowercase Unicode character values.
511
* <p>
6-
* Alphabetical order is a system whereby character strings are placed in order
7-
* based on the position of the characters in the conventional ordering of an
8-
* alphabet.
12+
* Non-letter characters are not allowed and will cause the check to fail.
913
* <p>
10-
* Reference: <a href="https://en.wikipedia.org/wiki/Alphabetical_order">Wikipedia: Alphabetical Order</a>
14+
* Reference:
15+
* <a href="https://en.wikipedia.org/wiki/Alphabetical_order">Wikipedia: Alphabetical order</a>
1116
*/
1217
public final class Alphabetical {
18+
1319
private Alphabetical() {
1420
}
1521

1622
/**
17-
* Checks whether the characters in the given string are in alphabetical order.
18-
* Non-letter characters will cause the check to fail.
23+
* Checks whether the characters in the given string are in non-decreasing
24+
* lexicographical order (case-insensitive).
25+
* <p>
26+
* Rules:
27+
* <ul>
28+
* <li>String must not be null or blank</li>
29+
* <li>All characters must be letters</li>
30+
* <li>Comparison is based on lowercase Unicode values</li>
31+
* <li>Order must be non-decreasing (equal or increasing allowed)</li>
32+
* </ul>
1933
*
20-
* @param s the input string
21-
* @return {@code true} if all characters are in alphabetical order (case-insensitive), otherwise {@code false}
34+
* @param s input string
35+
* @return {@code true} if characters are in non-decreasing order, otherwise {@code false}
2236
*/
2337
public static boolean isAlphabetical(String s) {
24-
s = s.toLowerCase();
25-
for (int i = 0; i < s.length() - 1; ++i) {
26-
if (!Character.isLetter(s.charAt(i)) || s.charAt(i) > s.charAt(i + 1)) {
38+
if (s == null || s.isBlank()) {
39+
return false;
40+
}
41+
42+
String normalized = s.toLowerCase(Locale.ROOT);
43+
44+
if (!Character.isLetter(normalized.charAt(0))) {
45+
return false;
46+
}
47+
48+
for (int i = 1; i < normalized.length(); i++) {
49+
char prev = normalized.charAt(i - 1);
50+
char curr = normalized.charAt(i);
51+
52+
if (!Character.isLetter(curr) || prev > curr) {
2753
return false;
2854
}
2955
}
30-
return !s.isEmpty() && Character.isLetter(s.charAt(s.length() - 1));
56+
return true;
3157
}
3258
}
Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,54 @@
11
package com.thealgorithms.strings;
22

3+
import org.junit.jupiter.api.DisplayName;
4+
import org.junit.jupiter.api.Test;
5+
import org.junit.jupiter.params.ParameterizedTest;
6+
import org.junit.jupiter.params.provider.Arguments;
7+
import org.junit.jupiter.params.provider.MethodSource;
8+
9+
import java.util.stream.Stream;
10+
311
import static org.junit.jupiter.api.Assertions.assertEquals;
12+
import static org.junit.jupiter.params.provider.Arguments.arguments;
413

5-
import org.junit.jupiter.params.ParameterizedTest;
6-
import org.junit.jupiter.params.provider.CsvSource;
14+
@DisplayName("Alphabetical.isAlphabetical()")
15+
class AlphabeticalTest {
16+
17+
static Stream<Arguments> testCases() {
18+
return Stream.of(
19+
arguments("", false, "Should return false for empty string"),
20+
arguments(" ", false, "Should return false for blank string"),
21+
arguments("a1b2", false, "Should return false when string contains numbers"),
22+
arguments("abc!DEF", false, "Should return false when string contains symbols"),
23+
arguments("#abc", false, "Should return false when first character is not a letter"),
24+
arguments("abc", true, "Should return true for non-decreasing order"),
25+
arguments("aBcD", true, "Should return true for mixed case increasing sequence"),
26+
arguments("a", true, "Should return true for single letter"),
27+
arguments("'", false, "Should return false for single symbol"),
28+
arguments("aabbcc", true, "Should return true for repeated letters"),
29+
arguments("cba", false, "Should return false when order decreases"),
30+
arguments("abzba", false, "Should return false when middle breaks order")
31+
);
32+
}
33+
34+
private void assertAlphabetical(String input, boolean expected, String message) {
35+
// Arrange & Act
36+
boolean result = Alphabetical.isAlphabetical(input);
737

8-
public class AlphabeticalTest {
38+
// Assertion
39+
assertEquals(expected, result, message);
40+
}
41+
42+
@Test
43+
@DisplayName("Should return false for null input")
44+
void nullInputTest() {
45+
assertAlphabetical(null, false, "Should return false for null input");
46+
}
947

10-
@ParameterizedTest(name = "\"{0}\" → Expected: {1}")
11-
@CsvSource({"'abcdefghijklmno', true", "'abcdxxxyzzzz', true", "'123a', false", "'abcABC', false", "'abcdefghikjlmno', false", "'aBC', true", "'abc', true", "'xyzabc', false", "'abcxyz', true", "'', false", "'1', false"})
12-
void testIsAlphabetical(String input, boolean expected) {
13-
assertEquals(expected, Alphabetical.isAlphabetical(input));
48+
@ParameterizedTest(name = "{2}")
49+
@MethodSource("testCases")
50+
@DisplayName("Alphabetical cases")
51+
void isAlphabeticalTest(String input, boolean expected, String message) {
52+
assertAlphabetical(input, expected, message);
1453
}
1554
}

0 commit comments

Comments
 (0)