-2

I wrote a String class that masking username something like;

input --> Johny Holloway expecting output ---> J***y H***y

and its working.

However I like to change my code if user input name and surname less than 3 character

example; Name BR ---> B***R ; surName --> KL ---> K***L

How to change my code according to above example

My code is below;

public class MaskWords {

  public String mask(String str) {

    if (StringUtils.isBlank(str)) {
      return str;
    }

    String out = "";
    for (String d : str.split("\\s+")) {
      String startChar = d.substring(0, 1);
      String endChar = d.substring(d.length() - 1, d.length());
      out = out + startChar + "***" + endChar + " ";
    }
    return out.trim();
  }

  public List<String> mask(List<String> str) {
    List<String> maskedStringList = new ArrayList<>();
    for (String stringToMask : str) {
      maskedStringList.add(mask(stringToMask));
    }
    return maskedStringList;
  }  
Olaf Kock
  • 46,930
  • 8
  • 59
  • 90
  • 1
    Just test separately for a length of 2 characters. Don't do this using regular expressions, especially not with the regular expression that you started off with. Note that you haven't specified what to do with a single character name. – Maarten Bodewes Jan 02 '20 at 11:38
  • I know but I need to add an if conditions my code. How can ı do that. Thank you for reply – ercument ercuu Jan 02 '20 at 11:39
  • You seemed fine with that first IF you already wrote, so don't tell me you cannot do IF for exceptional cases. – Maarten Bodewes Jan 02 '20 at 11:40
  • Single character name should be like -> name : n -> n*** surname s-> s*** always 3 starts – ercument ercuu Jan 02 '20 at 11:40
  • Are you sure your code doesn't already run for two character strings, by the way? – Maarten Bodewes Jan 02 '20 at 11:45
  • org.opentest4j.AssertionFailedError: expected: but was: – ercument ercuu Jan 02 '20 at 11:54
  • Do pay attention: `J*a` can never be emitted by your code (tests can fail too), and `J***` is the special case *for one character names*, not two - so that one makes the test fail. – Maarten Bodewes Jan 02 '20 at 12:00
  • It's not clear from your question exactly what the expected output should be when a string of 2 characters is supplied. I'd suggest you add that to the question. – ajayian Jan 02 '20 at 13:11

1 Answers1

0

Treat the cases differently, for 2 chars it can be the same.

To make the code better, do not use char (UTF-16) but Unicode code points. Sometimes Unicode code points, symbols, use 2 chars: Chinese, emoji. So more general would be:

StringBuilder out = new StringBuilder(str.length + 10);
for (String d : str.split("\\s+")) {
    int codePoints = d.codePointCount(0, d.length());
    if (codePoints >= 2) {
        int startChar = d.codePointAt(0);
        int endChar = d.codePointBefore(d.length());
        out.appendCodePoint(startChar).append("***").appendCodePoint(endChar).append(' ');
    } else if (codePoints == 1) {
        out.append(d).append("***").append(' ');
        // Or: out.append("* ");
    }
}
return out.toString().trim();

With 1 code point, I made X*** (better *) but if so desired, X***X would be covered by the first if, for > 0.

StringBuilder is faster, and its appendCodePoint is usefull here.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • Note that personally I would have made this into two methods: one to split the names and one to mask a single name (`maskFullName` and a private `maskName` method, for instance). Logic like this quickly explodes with special cases, as you may have noticed. – Maarten Bodewes Jan 02 '20 at 12:07
  • Thank you, Why we (str.length() + 10); use this – ercument ercuu Jan 02 '20 at 12:11
  • Totally unneeded capacity parameter, but say for a final String of 10 000 chars, a growing StringBuilder would often reallocate to a larger internal `char[]` so that was an estimated guess to prevent the need to reallocate often. – Joop Eggen Jan 02 '20 at 12:18