From 43fa521d1450dd0a1646ef3d92809e1484598354 Mon Sep 17 00:00:00 2001 From: Adam Cowley Date: Mon, 11 Sep 2017 11:02:04 +0100 Subject: [PATCH] Added apoc.text.random(length, [valid_chars]) - Fixes #563 --- src/main/java/apoc/text/Strings.java | 27 +++++++++++++++++++++++- src/test/java/apoc/text/StringsTest.java | 24 +++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/main/java/apoc/text/Strings.java b/src/main/java/apoc/text/Strings.java index 4d9096e567..8e3b5f6720 100644 --- a/src/main/java/apoc/text/Strings.java +++ b/src/main/java/apoc/text/Strings.java @@ -11,11 +11,14 @@ import java.net.URLEncoder; import java.text.Normalizer; import java.util.*; +import java.util.concurrent.ThreadLocalRandom; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; + +import static java.lang.Math.toIntExact; import static java.util.Arrays.asList; /** @@ -197,7 +200,7 @@ public String format(@Name("text") String text, @Name("params") List par if (params == null) return text; return String.format(Locale.ENGLISH,text, params.toArray()); } - + @UserFunction @Description("apoc.text.slug(text, delim) - slug the text with the given delimiter") public String slug(@Name("text") String text, @Name(value = "delim", defaultValue = "-") String delim) { @@ -205,4 +208,26 @@ public String slug(@Name("text") String text, @Name(value = "delim", defaultValu if (delim == null) return null; return text.trim().replaceAll("[\\W\\s]+", delim); } + + + private static final String lower = "abcdefghijklmnopqrstuvwxyz"; + private static final String upper = lower.toUpperCase(); + private static final String numeric = "0123456789"; + + @UserFunction + @Description("apoc.text.random(length, valid) YIELD value - generate a random string") + public String random(final @Name("length") long length, @Name(value = "valid", defaultValue = "A-Za-z0-9") String valid) { + valid = valid.replaceAll("A-Z", upper).replaceAll("a-z", lower).replaceAll("0-9", numeric); + + StringBuilder output = new StringBuilder( toIntExact(length) ); + + ThreadLocalRandom rand = ThreadLocalRandom.current(); + + while ( output.length() < length ) { + output.append( valid.charAt( rand.nextInt(valid.length()) ) ); + } + + return output.toString(); + } + } diff --git a/src/test/java/apoc/text/StringsTest.java b/src/test/java/apoc/text/StringsTest.java index 535ad20f3a..2036683dd1 100644 --- a/src/test/java/apoc/text/StringsTest.java +++ b/src/test/java/apoc/text/StringsTest.java @@ -8,16 +8,20 @@ import org.neo4j.helpers.collection.Iterators; import org.neo4j.test.TestGraphDatabaseFactory; +import static java.lang.Math.toIntExact; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static apoc.util.MapUtil.map; import static apoc.util.TestUtil.testCall; import static apoc.util.TestUtil.testResult; import static org.junit.Assert.*; + /** * @author mh * @since 05.05.16 @@ -326,4 +330,24 @@ public void testSlug() { testCall(db, "RETURN apoc.text.slug('a- b','-') AS value", row -> assertEquals("a-b", row.get("value"))); testCall(db, "RETURN apoc.text.slug('a b c') AS value", row -> assertEquals("a-b-c", row.get("value"))); } + + @Test + public void testRandom() { + Long length = 10L; + String valid = "A-Z0-9"; + + testCall( + db, + "RETURN apoc.text.random({length}, {valid}) as value", + map("length", length, "valid", valid), + row -> { + String value = row.get("value").toString(); + + Pattern pattern = Pattern.compile("^(["+valid+"]{"+ toIntExact(length) +"})$"); + Matcher matcher = pattern.matcher(value); + + assertTrue("String +" +value+ "+ should match the supplied pattern "+ pattern.toString(), matcher.matches()); + } + ); + } }