Mask String with characters
Asked Answered
E

7

7

Hey guy's I tried to find a way to hide a string, but the code that I found just work with my application... Is there a way to hide the characters in a string with either * or - and if there is can someone please explain

Evapotranspiration answered 27/8, 2012 at 19:25 Comment(4)
What do you mean, "hide a string"? Can't you just display a string of "" the same length as the original? Do you only want to hide *some characters? Against a pattern? Length?Wherein
Yes, as Dave Newton said, there are ways to replaces portions of the string, or the entire string with whatever you please, but you'll have to be more specific about your desired result. Can you give us a specific example that shows the original string, and how you want it to look after your 'replacement'.Erratic
I have considered the replace char option but the I realized i would get stuck if there's two of the same chars. Basically what I'm trying to explain is the hangman concept, a line of ------ that represents the wordEvapotranspiration
What do you want preserved and what do you want to become * out of the following options: Chars, Nums, Spaces, Tabs, Just Letters, things like #$%^&@Aerograph
H
10

Is this for making a password? Consider the following:

class Password {
    final String password; // the string to mask
    Password(String password) { this.password = password; } // needs null protection
    // allow this to be equal to any string
    // reconsider this approach if adding it to a map or something?
    public boolean equals(Object o) {
        return password.equals(o);
    }
    // we don't need anything special that the string doesnt
    public int hashCode() { return password.hashCode(); }
    // send stars if anyone asks to see the string - consider sending just
    // "******" instead of the length, that way you don't reveal the password's length
    // which might be protected information
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for(int i = 0; < password.length(); i++) 
            sb.append("*");
        return sb.toString();
    }
}

Or for the hangman approach

class Hangman {
    final String word;
    final BitSet revealed;
    public Hangman(String word) {
        this.word = word;
        this.revealed = new BitSet(word.length());
        reveal(' ');
        reveal('-');
    }
    public void reveal(char c) {
        for(int i = 0; i < word.length; i++) {
            if(word.charAt(i) == c) revealed.set(i);
        }
    }
    public boolean solve(String guess) {
        return word.equals(guess);
    }
    public String toString() {
         StringBuilder sb = new StringBuilder(word.length());
         for(int i = 0; i < word.length; i++) {
             char c = revealed.isSet(i) ? word.charAt(i) : "*";
         }
         return sb.toString();
    }
}
Hesler answered 27/8, 2012 at 19:32 Comment(0)
F
5

Just create a string with the same number of characters as your original, with instead your "obfuscating" character.

String x = "ABCD";

String output = "";
for (int i = 0; i < x.length(); i++) {
    output += "*";
}

Alternatively you could use x.replaceAll("\\S", "*"), which would preserve whitespace as well.

Frolic answered 27/8, 2012 at 19:37 Comment(11)
You need to check for all white space and non-whitespace characters. So the regex would be [\s\S]Usury
@Usury No, I specifically said that using replaceAll with the pattern I mentioned "would preserve whitespace". That is, would only replace non-whitespace characters with an asterisk. So "hello world" would become "***** *****". The regex you provided would not preserve the whitespace.Frolic
The question is "Is there a way to hide the characters in a string with either "*" or "-" and if there is can someone please explain"Usury
Which is why the replaceAll was suggested as as alternative which would preserve whitespace if so desired. The previous for-loop would replace all characters.Frolic
I think you are answering a question that is not even asked.Usury
Only if the English language has changed significantly since the OP said "is there a way to hide the characters in a string with either "*" or "-"?". The for-loop iterates through the string and replaces each character with '*'.Frolic
Yes, but if you are offering an alternative, why would you use the \S pattern over the [\s\S]. How is preserving whitespace in a password legit, when and where is that ever done? You answer is non sense.Usury
@Usury -- Please indicate where in the OP it indicates that this is a password. The OP only says that they wish to hide the characters. I provided two options -- one for hiding all characters, one for hiding the non-white-space characters. Frankly, \s\S is no more correct: to hide all characters including white space, the correct pattern to use would be .Frolic
where in the OP it indicates that this is a password: https://mcmap.net/q/1322179/-mask-string-with-charactersUsury
It's a link to the answer, not an answer. The OP is the only one who can mark the correct answer.Usury
And yet that answer provides two solutions: one that assumes it's a password (hides spaces) and one that preserves whitespace (the "hangman approach").Frolic
U
2

There are several ways to achieve this, it would depend on your application.

If you want to mask all characters with another character in one fell swoop you can use the String#replaceAll(String regex, String replacement) method: http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replaceAll(java.lang.String,%20java.lang.String).

This involves using Regular Expressions, for regex you would use [\s\S] which will match any whitespace or non whitespace character. For replacement you use a regular string, not a RegEx. In this case, if you wanted an asterisk, use "*", for hyphen "-", very simple.

All the other methods here work well except the @Roddy of the Frozen Pea and @djc391 ones, so that's why I answered it correctly.

Good luck

Usury answered 1/2, 2014 at 16:17 Comment(0)
R
1

You could easily implement something like this:

public class MaskedString
{
    private String data;

    public MaskedString(String data){this.data = data;}
    public void append(char c){data += c;}
    public void setData(String data){this.data = data;}

    public String getMasked()
    {
        StringBuilder sb = new StringBuilder();
        for(int i=0; i<data.length(); i++)
            sb.append('*');
        return sb.toString();
    }

    public String getString()
    {
        return data;
    }
}

You get the idea :)

Repro answered 27/8, 2012 at 19:49 Comment(0)
A
0

My implementation:

public static String maskString(String s, int x) {
    int n = s.length()/x;
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < s.length(); i++) {
      if (n >= 1 && (i < n || i >= (s.length() - n))) {
        sb.append(s.charAt(i));
      }
      else {
        sb.append("*");
      }
    }
    return sb.toString();
  }
Allelomorph answered 12/3, 2020 at 2:47 Comment(0)
R
0

This is a generic way of masking and it can be used to mask an entire String or a particular portion of the String.

Parameters required

  1. data -> The String that needs to be masked.
  2. from -> Index from where the masking should start.
  3. to -> Index till where the masking should continue.
  4. maskWith -> Character with which you want to mask.

The first thing is to get the masked data, using a for loop starting with from and ending with to, inside the loop append the maskWith to a StringBuilder. Now, you need to get the portion from the data that needs to be masked, you can use the substring method with from and to as arguments respectively. Finally, use the replace method by supplying the above substring as the first argument and the masked String as the second argument.

Code

public static String maskData(String data, int from, int to, char maskWith) {
        
    StringBuilder maskedPart = new StringBuilder();
    for(int i=from; i<to; i++)
        maskedPart.append(maskWith);
        
    return data.replace(data.substring(from, to), maskedPart.toString());
}

Sample value

public static void main(String[] args) {
    System.out.println(maskData("9999123456789999", 4, 12, 'X'));
}

Output

9999XXXXXXXX9999
Rewrite answered 12/7 at 5:23 Comment(0)
C
-1

If you are looking for simple implementation, you can use below function:

Kotlin:

fun String.mask(
        maskString: String = "x",
        maskAfterLetters: Int = 3,
        isFixSize: Boolean = true,
        maxSize: Int = 10,
        selector: String = "."
): String {
    if(maskAfterLetters < 0) throw IllegalArgumentException("Invalid masking configuration - maskAfterLetters should be greater than 0")
    if(isFixSize && maxSize <= maskAfterLetters) throw IllegalArgumentException("Invalid masking configuration - maxSize must be greater than maskAfterLetters")
    val text = if(isFixSize && length >= maxSize) substring(0, maxSize) else this
    val unmaskLength = if(maskAfterLetters <= length) maskAfterLetters else length
    return text.substring(0, unmaskLength) + text.substring(unmaskLength, text.length).replace(selector.toRegex(), maskString)
}

Java:

/* 
For Java,
Additional input parameter named inputStringToBeMasked which is the actual string which has to be masked.
*/

    public static String mask(
            String inputStringToBeMasked,
            String maskString,
            Integer maskAfterLetters,
            Boolean isFixSize,
            Integer maxSize,
            String selector
    ) {
        //check input and set default if input parameters are not passed
        if(null == maskString || maskString.isEmpty()) maskString = "x";
        if(null == maskAfterLetters) maskAfterLetters = 3;
        if(null == isFixSize) isFixSize = true;
        if(null == maxSize) maxSize = 10;
        if(null == selector || selector.isEmpty()) selector = ".";
        if(maskAfterLetters < 0) throw new IllegalArgumentException("Invalid masking configuration - maskAfterLetters should be greater than 0");
        if(isFixSize && maxSize <= maskAfterLetters) throw new IllegalArgumentException("Invalid masking configuration - maxSize must be greater than maskAfterLetters");

        String text = (isFixSize && inputStringToBeMasked.length() >= maxSize) ? inputStringToBeMasked.substring(0, maxSize) : inputStringToBeMasked;
        Integer unmaskLength = (maskAfterLetters <= inputStringToBeMasked.length()) ? maskAfterLetters : inputStringToBeMasked.length();
        return text.substring(0, unmaskLength) + text.substring(unmaskLength, text.length()).replaceAll(selector, maskString);
    }

Note: This method in Kotlin, you can covert it in Java easily.

where,

  • maskString: is an string which is to be replaced with characters being masked
  • maskAfterLetters: initial given letters are kept original and then masking started
  • isFixSize: is given masked result with fixed size of based on input string size
  • maxSize: if isFixSize is true then provided the size of masked string
  • selector: (no change needed) used for selection of characters to be masked

If you are looking for automated masking while serialization and deserialization, you can use json-masker which is an annotation based making solution.

Curbing answered 11/9, 2023 at 5:4 Comment(2)
Though Kotlin is a cool language, this question was about Java. Would be nicer of you if you indeed converted your code to Java instead of mentioning it.Bors
@Bors Provided Java implementation as well, hope it will help you.Curbing

© 2022 - 2024 — McMap. All rights reserved.