Skip to content

Commit a7006a8

Browse files
committed
word(String)
1 parent 154cd30 commit a7006a8

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

dot-parse/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,10 @@ Stream<String> jsonStringsFrom(Reader input) {
316316
}
317317
```
318318

319+
Note that JSON supports Unicode escape. But we don't need to care because we are just splitting by calling
320+
`.source()` after finding the split point. The parser translating a unicode escape correctly or not
321+
is irrelevant.
322+
319323
## Example — Mini Search Language
320324

321325
Imagine you are building your own search engine, and you want to allow users to search by search terms.

dot-parse/src/main/java/com/google/common/labs/parse/Parser.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@ public static Parser<String> chars(int n) {
161161
};
162162
}
163163

164+
/**
165+
* {@code word("equal")} matches "equal" but not "equals".
166+
*
167+
* @since 9.4
168+
*/
169+
public static Parser<String> word(String word) {
170+
return string(word).notImmediatelyFollowedBy(CharPredicate.WORD, "[a-zA-Z0-9_]");
171+
}
172+
164173
/**
165174
* One or more regex {@code \w+} characters.
166175
*
@@ -242,7 +251,7 @@ public static Parser<String> quotedStringWithEscapes(
242251
*
243252
* will return the emoji {@code 😀}.
244253
*
245-
* <p>You can also use it together with {@link #quotedStringWithEscapes}:
254+
* <p>You can also compose it with {@link #quotedStringWithEscapes}:
246255
*
247256
* <pre>{@code
248257
* quotedStringWithEscapes('"', string("u").then(codePoint()).map(Character::toString));

dot-parse/src/test/java/com/google/common/labs/parse/ParserTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,40 @@ public void string_cannotBeEmpty() {
8383
assertThrows(IllegalArgumentException.class, () -> string(""));
8484
}
8585

86+
@Test
87+
public void word_success() {
88+
assertThat(word("foo").parse("foo")).isEqualTo("foo");
89+
}
90+
91+
@Test
92+
public void word_failIfFollowedByWordChar() {
93+
assertThrows(ParseException.class, () -> word("foo").parse("foobar"));
94+
assertThrows(ParseException.class, () -> word("foo").parse("foo_bar"));
95+
assertThrows(ParseException.class, () -> word("foo").parse("foo1"));
96+
}
97+
98+
@Test
99+
public void word_successIfNotFollowedByWordChar() {
100+
assertThat(word("foo").probe("foo?")).containsExactly("foo");
101+
assertThat(word("foo").probe("foo-")).containsExactly("foo");
102+
}
103+
104+
@Test
105+
public void word_skipping_success() {
106+
assertThat(word("foo").skipping(Character::isWhitespace).parseToStream("foo")).containsExactly("foo");
107+
assertThat(word("foo").skipping(Character::isWhitespace).parseToStream("foo foo"))
108+
.containsExactly("foo", "foo");
109+
assertThat(word("foo").skipping(Character::isWhitespace).probe(" foo-foo")).containsExactly("foo");
110+
}
111+
112+
@Test
113+
public void word_skipping_failIfFollowedByWordChar() {
114+
assertThrows(ParseException.class, () -> word("foo").parseSkipping(Character::isWhitespace, "foobar"));
115+
assertThrows(ParseException.class, () -> word("foo").parseSkipping(Character::isWhitespace, "foo_bar"));
116+
assertThrows(ParseException.class, () -> word("foo").parseSkipping(Character::isWhitespace, "foo1"));
117+
assertThrows(ParseException.class, () -> word("foo").parseSkipping(Character::isWhitespace, " foo1"));
118+
}
119+
86120
@Test
87121
public void testNulls() {
88122
NullPointerTester tester =

0 commit comments

Comments
 (0)