megami
megami

Reputation: 69

Random characters java

I have to make a text file in which I'm supposed to put 100 random characters where on each even position should be a small letter and on each odd position should be a capital letter. Also, all the letters are supposed to be separated by a blank field (space). I only succeeded to make a 100 random characters list but I don't know how to do the rest.

public class Main {

    public static char getRandomCharacter(char c1, char c2) {
        return (char) (c1 + Math.random() * (c2 - c1 + 1));
    }

    public static char[] createArray() {
        char[] character = new char[100];
        for (int i = 0; i < character.length; i++) {
            character[i] = getRandomCharacter('a', 'z');
        }
        for (int i = 0; i < character.length; i++) {
            System.out.println(character[i]);
        }
        return character;
    }

    public static void main(String[] args) {
        createArray();

    }

}

I would appreciate the help.

EDIT: Here's an edited version. However, the output is not much different b j r m r b k i...

public class Main {

    public static char getRandomCharacter(char c1, char c2) {
        return (char) (c1 + Math.random() * (c2 - c1 + 1));
    }

    public static char[] createArray() {
        char[] character = new char[100];
        for (int i = 0; i < character.length; i++) {
            character[i] = getRandomCharacter('a', 'z');
        }
        for (int i = 0; i < character.length; i++) {
            System.out.println(character[i]);
        }
        return character;
    }

    public static void main(String[] args) {
        char[] arr = createArray();
        StringBuilder text = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            int pos = i + 1;
            if (pos % 2 != 0) {
                String s = "" + arr[i];
                text.append(s.toUpperCase());
            } else {
                text.append(arr[i] + " ");
            }
        }
        String content = text.toString().trim();

    }

}

Upvotes: 2

Views: 853

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 338775

Code point

The Answer by WJS looks correct. But, unfortunately, the char type is legacy. As a 16-bit value, the char type is physically incapable of representing most characters. So I recommend making a habit of using code point integer numbers instead of char.

IntSupplier for IntStream of code points

Also, I happened to notice the method IntStream.generate that takes an IntSupplier. We can write our own implementation of that interface IntSupplier that alternates between returning a code point number for an uppercase letter and returning a code point for a lowercase letter.

Within our implementation we define an enum of two objects, to represent uppercase and lowercase.

Our implementation has a constructor taking either of those two enum objects. The passed argument signals the case of the first letter to be generated.

package work.basil.example.rando;

import java.util.concurrent.ThreadLocalRandom;
import java.util.function.IntSupplier;

public class SupplierOfCodePointForBasicLatinLetterInAlternatingCase
        implements IntSupplier
{
    public enum LetterCase { UPPERCASE, LOWERCASE }

    private LetterCase currentCase;

    public SupplierOfCodePointForBasicLatinLetterInAlternatingCase ( final LetterCase startingCase )
    {
        this.currentCase = startingCase;
    }

    @Override
    public int getAsInt ( )
    {
        int codePoint =
                switch ( this.currentCase )
                        {
                            case UPPERCASE -> ThreadLocalRandom.current().nextInt( 65 , 91 ); // ( inclusive , exclusive )
                            case LOWERCASE -> ThreadLocalRandom.current().nextInt( 97 , 123 );
                        };
        this.currentCase =
                switch ( this.currentCase )
                        {
                            case UPPERCASE -> LetterCase.LOWERCASE;
                            case LOWERCASE -> LetterCase.UPPERCASE;
                        };
        return codePoint;
    }
}

When we invoke our customized IntStream, we pass a limit of the number of code points to generate.

Finally, we collect all the generate code points into a StringBuilder from which we build our final resulting String object.

IntStream streamOfCodePoints = IntStream.generate( new SupplierOfCodePointForBasicLatinLetterInAlternatingCase( SupplierOfCodePointForBasicLatinLetterInAlternatingCase.LetterCase.UPPERCASE ) );
String result =
        streamOfCodePoints
                .limit( 100 )
                .collect( StringBuilder :: new , StringBuilder :: appendCodePoint , StringBuilder :: append )
                .toString();

ZtAxIqWfEhOeHdSgOpMyPuJwLuSwJqHzUwSlLeQnFoFcAaMfOxMiBnVuZxOpCvPuLiZhBmIrGaBqZzIyOoUhAdFmXgArVwWqBoWr

Adding SPACE

Your requirements specify that each generated letter be separated by a space.

Somewhere define a constant for the code point of 32 for the SPACE character.

private static final int SPACE = 32; // ASCII & Unicode code point for SPACE character is 32 decimal.

Then alter our .collect line to use expanded syntax. Instead of a method reference, we use a lambda. In that lambda, we call StringBuilder#appendCodePoint twice. In the first call we append the generate code point. In the second call we append the SPACE character’s code point.

To eliminate the SPACE at the very end, we trim.

IntStream streamOfCodePoints = IntStream.generate( new SupplierOfCodePointForBasicLatinLetterInAlternatingCase( SupplierOfCodePointForBasicLatinLetterInAlternatingCase.LetterCase.UPPERCASE ) );
String result =
        streamOfCodePoints
                .limit( 100 )
                .collect(
                        StringBuilder :: new ,
                        ( stringBuilder , codePoint ) -> stringBuilder.appendCodePoint( codePoint ).appendCodePoint( App.SPACE ) ,
                        StringBuilder :: append
                )
                .toString()
                .trim() ;

X t D j J g J m Y c J a E e H m U c H b U a R t J g R n G r V s P e B z D k G f H e Z r W t U l U f C z R j F z G k Z f A y I z N i L g Q y Q w D w D w P s F y E n J n I i R b B u H x U m B g K w C k

If you want to keep the SPACE on the end, drop the call to String#trim.

Upvotes: 2

WJS
WJS

Reputation: 40044

Here is an alternative approach using Streams of ASCII characters. In the ASCII table, a-z are adjacent as are A-Z. So for any value d from 0 to 25, (char)(d + 'a') will be a lower case letter and (char)(d + 'A') will be an upper case letter.

  • create a Random instance.
  • stream the integers from 0 to 100 for 100 characters.
  • check the parity of i and add either 'a' or 'A' to the value d
  • map to a String and join using a space as a delimiter.

Random r = new Random();
String str = IntStream.range(0,100).mapToObj(
        i -> {
            int d = r.nextInt(26);
            return String.valueOf((char)(i % 2 == 0 ? d + 'a' : d +  'A'));
        }).collect(Collectors.joining(" "));

System.out.println(str);

prints something similar to

j H o C y X h H k A y F z J b D x A z R t Y w O d A a F q F t R n A i B k Y g F 
y X c O r I h E k K t R n L a S d C s T m S z Y z H a V y N o R t S y I t E l W 
q X l E v S h D r C y N h O o C l D u X

To write to a file, use try with resources and also catch IO errors.

String file = "f:/myOutputFile.txt";
try (FileWriter output = new FileWriter(new File(file))) {
    output.write(str);
} catch (IOException ioe) {
    ioe.printStackTrace();
}

Here is how you could do it with a simple loop.

  • initialize a StringBuilder to the a lower case letter for the 0th location which is even. This also allows prepending the space to avoid a trailing space at the end.
  • Then iterate from 1 to 100 to get the other 99 characters.
  • first append the space, then append the appropriate character as was done in the previous example.
  • Then you can write the StringBuilder as a string as shown above.
StringBuilder sb =
        new StringBuilder().append((char) (r.nextInt(26) + 'a'));
for (int i = 1; i < 100; i++) {
    int d = r.nextInt(26);
    sb.append(" ")
            .append((char) (i % 2 == 0 ? d + 'a' : d + 'A'));
}

Upvotes: 1

Sayan Bhattacharya
Sayan Bhattacharya

Reputation: 1368

In your case it's easier to create a string first and then put it into a txt file.

You can simply iterate through the random array and check for odd/even positions. Use Character.toUpperCase or Character.toLowercase in respective odd even postion and append to the string.

Use StringBuilder so that you don't have to create new String objects every time.

char[] arr = createArray();
StringBuilder text = new StringBuilder();
//iterate thoruh the arr
for (int i = 0; i < arr.length; i++) {
    int pos = i+1;
    if(pos%2!=0){  // check whether current postion is odd or even                 
        text.append(Character.toUpperCase(arr[i])+" ");// if position is odd then convert it to uppercase
    }else{
        text.append(arr[i]+" ");  // if position is even then convert it toLowercase if needed (if arr contents both upper case and lower case)
    }
}
String content = text.toString().trim(); // trimin to remove any extra space in last or first of the string.

To write in file

String path = "D:/a.txt";
Files.write( Paths.get(path), content.getBytes());

EDIT 1 : I am not sure why this Character.toUpperCase is not working. You can try this below conversion, the drawback is that a String object will be created for every even position.

String s = ""+ arr[i];
text.append(s.toUpperCase()+" ");

EDIT 2: You can use normal String

String text = "";
for (int i = 0; i < arr.length; i++) {
    int pos = i + 1;
    if (pos % 2 != 0) {
        String s = "" + arr[i];
        text =text + s.toUpperCase()+" ";
    } else {
        text= text + (arr[i] + " ");
    }
}
String content = text.toString().trim();
System.out.println(content);

Upvotes: 0

Related Questions