0

I have a Set<> of strings:

Set<String> mySet = new HashSet<String>();
    
hs.add("how");
hs.add("are");
hs.add("you");

I want to turn this set into a string, however there is two rules:

  1. ":*" should be added as suffix to each word
  2. The words should be separated with a pipe |

Like this:

"how:*|are:*|you:*"

What is the most simple way to do this?

This is what I've tried so far:

StringBuilder sb = new StringBuilder();

for (String word : search) {
    sb.append(word);
    sb.append(":*|");
}

The problem with this is that it gives an extra pipe in the end:

"how:*|are:*|you:*|"

I can of course delete the last character, but I'm looking for a simpler way if possible.

TheStranger
  • 1,387
  • 1
  • 13
  • 35
  • What way have you tried so far? Can you show it please? – deHaar Jul 23 '21 at 07:23
  • 1
    Have you tried anything yet? Since you tagged `StringBuilder`, it seems like you already have an idea? – maloomeister Jul 23 '21 at 07:23
  • 1
    Stream, map x -> x + `":*"`, collect joining with `'|'` – Federico klez Culloca Jul 23 '21 at 07:24
  • 1
    @deHaar I've updated the post. – TheStranger Jul 23 '21 at 07:29
  • Specifically, the stream solution will work for all collections - e.g. with a [`Collector.joining`](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/stream/Collectors.html#joining(java.lang.CharSequence,java.lang.CharSequence,java.lang.CharSequence)), which allows to specify delimiter, prefix and postfix. – Hulk Jul 23 '21 at 07:30
  • One remark: if the result is used as regular expression: do not forget the word boundary matchers: `"\\b(" + ... + ")\\b"` so `do` and `does` match both. – Joop Eggen Jul 23 '21 at 07:36

2 Answers2

2

If you're using Java 8 or later, then String#join is one option. However, you should use an ordered collection to ensure that the strings appear in the order you want:

List<String> myList = Arrays.asList(new String[] { "how", "are", "you" });
String output = String.join(":*|", myList) + ":*";
System.out.println(output);  // how:*|are:*|you:*

You have revealed that you are trying to build a regex alternation to search for a term in your database. If so, then you should be using this pattern:

.*\b(?:how:|are:|you:).*

The leading and trailing .* might be optional, in the case where the API accepts a pattern matching just a portion of the column. Here is the updated Java code to generate this pattern:

List<String> myList = Arrays.asList(new String[] { "how", "are", "you" });
StringBuilder sb = new StringBuilder();
sb.append(".*\\b(?:").append(String.join(":|", myList)).append(":).*");
System.out.println(sb.toString);  // .*\b(?:how:|are:|you:).*
Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • 3
    @Ben Though be careful, you're using an HashSet. There's no guarantee you will see "how are you", you may as well see "how you are", "you how are", "are how you"... Tim's answer would be better applied to a Linked Hash Set if you care about insertion order. – Matteo NNZ Jul 23 '21 at 07:30
  • Perfect, it works. The order does not matter. I'm using the string to search in a column in the database. As long as it contains those words the order is irrelevant.. Thank you very much. – TheStranger Jul 23 '21 at 07:39
  • 1
    @Ben Check the updated answer for what you should be doing here. Use an alternation of the keywords, with word boundaries on both sides of that alternation. The leading and trailing `.*` are optional, provided the regex API you are calling can handle a partial match. – Tim Biegeleisen Jul 23 '21 at 07:44
0

Just looking at the problem with the pipe at the end, you could treat it as something added before each word except the first. It is often easier to identify the first element than the last element.

This is a small piece of pseudocode to show the idea:

separator = "|"
firstWord <– true
for each word in source {
  if (firstWord) {
    firstWord <– false
  } else {
    outString.append(separator)
  }
  outString.append(word + ";*)
}
rossum
  • 15,344
  • 1
  • 24
  • 38
  • I completely get that, but that was exactly what I wanted to avoid. I can do all of that in one line: String.join(":*|", search) + ":*"; – TheStranger Jul 23 '21 at 08:11
  • I get what you are saying, however that was exactly what I was trying to avoid. I want a simple solution. So Tim suggested one line that does all of that `String.join(":*|", mySet) + ":*";` – TheStranger Jul 23 '21 at 08:15