CORE
HOME > JAVA > J2SE > CORE
2020.10.03 / 18:13

java - util - random string generator alphanumeric

추석돌이
추천 수 8

임의의 문자열을 사용하는이 코드가 "hello world"를 인쇄하는 이유는 무엇입니까? (10)

Denis Tulskiy answer 대한 사소한 개선이 있습니다. 시간을 반으로 줄인다.

public static long[] generateSeed(String goal, long start, long finish) {
    char[] input = goal.toCharArray();

    int[] dif = new int[input.length - 1];
    for (int i = 1; i < input.length; i++) {
        dif[i - 1] = input[i] - input[i - 1];
    }

    mainLoop:
    for (long seed = start; seed < finish; seed++) {
        Random random = new Random(seed);
        int lastChar = random.nextInt(27);
        int base = input[0] - lastChar;
        for (int d : dif) {
            int nextChar = random.nextInt(27);
            if (nextChar - lastChar != d) {
                continue mainLoop;
            }
            lastChar = nextChar;
        }
        if(random.nextInt(27) == 0){
            return new long[]{seed, base};
        }
    }

    throw new NoSuchElementException("Sorry :/");
}

다음 print 문은 "hello world"를 인쇄합니다. 아무도 이것을 설명 할 수 있을까요?

System.out.println(randomString(-229985452) + " " + randomString(-147909649));

그리고 randomString() 은 다음과 같습니다.

public static String randomString(int i)
{
    Random ran = new Random(i);
    StringBuilder sb = new StringBuilder();
    while (true)
    {
        int k = ran.nextInt(27);
        if (k == 0)
            break;

        sb.append((char)('`' + k));
    }

    return sb.toString();
}

Java 문서에서 이것은 Random 클래스의 시드 값을 지정할 때 의도적 인 기능입니다.

무작위의 두 인스턴스가 동일한 시드로 만들어지고 동일한 메서드 호출 시퀀스가 ​​각각 만들어지면 동일한 숫자 시퀀스가 ​​생성되어 반환됩니다. 이 프로퍼티를 보증하기 위해서, 특정의 알고리즘이 클래스 Random에 대해 지정됩니다. 자바 구현은 Java 코드의 절대 이식성을 위해 Random 클래스에 대해 여기에 표시된 모든 알고리즘을 사용해야합니다.

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Random.html

이상하지만 예상 할 수있는 '임의의'숫자가있는 경우 암시적인 보안 문제가 있다고 생각할 수 있습니다.


Random은 항상 같은 순서를 리턴합니다. 배열과 다른 연산을 순열로 사용합니다.

다른 시퀀스를 얻으려면 "seed"라고하는 어떤 위치에서 시퀀스를 초기화해야합니다.

randomSting은 "임의"시퀀스의 i 위치 (시드 = -229985452)에 임의의 숫자를 가져옵니다. 그런 다음이 값이 0이 될 때까지 시드 위치 뒤의 시퀀스에서 다음 27 문자의 ASCII 코드를 사용합니다. 이렇게하면 "hello"가 반환됩니다. 같은 작업이 "세계"에 대해 수행됩니다.

나는 그 코드가 다른 어떤 단어들에서도 작동하지 않는다고 생각한다. 무작위 순서를 잘 알고있는 프로그래밍 된 사람.

그것은 아주 훌륭한 괴짜 코드입니다!


그것은 "씨앗"에 관한 것입니다. 같은 씨앗도 같은 결과를냅니다.


나는 이것에 흥미를 느꼈다. 나는이 임의의 단어 생성기를 사전 단어 목록에 올려 놓았다. 범위 : Integer.MIN_VALUE - Integer.MAX_VALUE

나는 15131의 히트를 얻었다.

int[] arrInt = {-2146926310, -1885533740, -274140519, 
                -2145247212, -1845077092, -2143584283,
                -2147483454, -2138225126, -2147375969};

for(int seed : arrInt){
    System.out.print(randomString(seed) + " ");
}

인쇄물

the quick browny fox jumps over a lazy dog 

나는이 씨앗을 찾는 빠른 프로그램을 썼다.

import java.lang.*;
import java.util.*;
import java.io.*;

public class RandomWords {
    public static void main (String[] args) {
        Set<String> wordSet = new HashSet<String>();
        String fileName = (args.length > 0 ? args[0] : "/usr/share/dict/words");
        readWordMap(wordSet, fileName);
        System.err.println(wordSet.size() + " words read.");
        findRandomWords(wordSet);
    }

    private static void readWordMap (Set<String> wordSet, String fileName) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader(fileName));
            String line;
            while ((line = reader.readLine()) != null) {
                line = line.trim().toLowerCase();
                if (isLowerAlpha(line)) wordSet.add(line);
            }
        }
        catch (IOException e) {
            System.err.println("Error reading from " + fileName + ": " + e);
        }
    }

    private static boolean isLowerAlpha (String word) {
        char[] c = word.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (c[i] < 'a' || c[i] > 'z') return false;
        }
        return true;
    }

    private static void findRandomWords (Set<String> wordSet) {
        char[] c = new char[256];
        Random r = new Random();
        for (long seed0 = 0; seed0 >= 0; seed0++) {
            for (int sign = -1; sign <= 1; sign += 2) {
                long seed = seed0 * sign;
                r.setSeed(seed);
                int i;
                for (i = 0; i < c.length; i++) {
                    int n = r.nextInt(27);
                    if (n == 0) break;
                    c[i] = (char)((int)'a' + n - 1);
                }
                String s = new String(c, 0, i);
                if (wordSet.contains(s)) {
                    System.out.println(s + ": " + seed);
                    wordSet.remove(s);
                }
            }
        }
    }
}

나는 그것을 배경으로 사용하고 있지만, 이미 고전적인 팡글에는 충분한 단어가있다.

import java.lang.*;
import java.util.*;

public class RandomWordsTest {
    public static void main (String[] args) {
        long[] a = {-73, -157512326, -112386651, 71425, -104434815,
                    -128911, -88019, -7691161, 1115727};
        for (int i = 0; i < a.length; i++) {
            Random r = new Random(a[i]);
            StringBuilder sb = new StringBuilder();
            int n;
            while ((n = r.nextInt(27)) > 0) sb.append((char)('`' + n));
            System.out.println(sb);
        }
    }
}

이데온 데모. )

추신. -727295876, -128911, -1611659, -235516779 .


대부분의 난수 생성기는 사실 "의사 랜덤 (pseudo random)"입니다. 그들은 Linear Congruential Generators 또는 LCG입니다 ( http://en.wikipedia.org/wiki/Linear_congruential_generator ).

고정 된 종자가 주어진다면 LCG는 꽤 예측 가능합니다. 기본적으로 첫 번째 문자를 제공하는 시드를 사용하고 대상 문자열의 다음 문자를 치고 LCG를 호출 한 횟수를 기록 할 때까지 다음 int (char)를 계속 생성하는 앱을 작성합니다. 각 문자를 생성 할 때까지 계속하십시오.


여기있는 모든 사람들은 코드가 작동하는 방식을 설명하고 자신 만의 예제를 구성하는 방법을 보여 주었지만 무차별 대항 검색이 결국에는 찾을 수있는 솔루션이 합리적으로 기대할 수있는 이유를 보여주는 정보 이론적 답변을 제공합니다.

26 개의 소문자는 알파벳 Σ 합니다. 다른 길이의 단어를 생성 할 수 있도록 종결 기호  를 추가하여 확장 알파벳 Σ' := Σ ∪ {⊥} 합니다.

α 기호로, X를 Σ' 대해 균일하게 분포 된 확률 변수 라하자. 그 심볼 P(X = α) 와 그것의 정보 내용 I(α) 를 얻을 확률은 다음과 같이 주어진다 :

P (X = α) = 1 / | Σ '| = 1 / 27

I (α) = -log2 [P (X = α)] = -log2 (1/27) = log2 (27)

ω ∈ Σ* 라는 단어와 ⊥- 종결 된 상대 ω' := ω · ⊥ ∈ (Σ')* 에 대해 우리는

I (ω) : = I (ω ') = | ω'| * log2 (27) = (| ω | + 1) * log2 (27)

의사 랜덤 넘버 생성기 (PRNG)는 32 비트 시드로 초기화되므로, 최대 길이의 단어가

λ = 플로어 [32 / log2 (27)] - 1 = 5

적어도 하나의 시드에 의해 생성됩니다. 6 자 단어를 검색하더라도 41.06 %의 성공률을 보입니다. 너무 초라한.

7 글자는 1.52 %에 가깝습니다. 그러나 그것을 시도하기 전에 깨닫지 못했습니다.

#include <iostream>
#include <random>

int main()
{
    std::mt19937 rng(631647094);
    std::uniform_int_distribution<char> dist('a', 'z' + 1);

    char alpha;
    while ((alpha = dist(rng)) != 'z' + 1)
    {
        std::cout << alpha;
    }
}

출력을보십시오 : http://ideone.com/JRGb3l


java.util.Random 의 인스턴스가 특정 시드 매개 변수 (이 경우 -229985452 또는 -147909649 )로 생성되면 해당 시드 값으로 시작 하는 난수 생성 알고리즘을 따릅니다.

동일한 시드로 생성 된 모든 Random 은 매 번 동일한 패턴의 패턴을 생성합니다.


Denis Tulskiy 의 답변에서 파생 된이 메서드는 시드를 생성합니다.

public static long generateSeed(String goal, long start, long finish) {
    char[] input = goal.toCharArray();
    char[] pool = new char[input.length];
    label:
        for (long seed = start; seed < finish; seed++) {
            Random random = new Random(seed);

            for (int i = 0; i < input.length; i++)
                pool[i] = (char) (random.nextInt(27)+'`');

            if (random.nextInt(27) == 0) {
                for (int i = 0; i < input.length; i++) {
                    if (input[i] != pool[i])
                        continue label;
                }
                return seed;
            }

        }