java - لماذا يطبع هذا الرمز باستخدام سلاسل عشوائية "hello world"؟




string random (13)

طباعة البيان التالي طباعة "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();
}

Answers

هنا هو تحسين طفيف لإجابة دنيس Tulskiy. تقطع الوقت بمقدار النصف

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 :/");
}

تشرح الإجابات الأخرى السبب ، ولكن هنا كيف.

نظرا لمثل Random :

Random r = new Random(-229985452)

الأرقام 6 الأولى التي r.nextInt(27) :

8
5
12
12
15
0

والأرقام الستة الأولى التي r.nextInt(27) المعطى Random r = new Random(-147909649) هي:

23
15
18
12
4
0

ثم أضف فقط تلك الأرقام إلى التمثيل الصحيح للحرف ` (وهو 96):

8  + 96 = 104 --> h
5  + 96 = 101 --> e
12 + 96 = 108 --> l
12 + 96 = 108 --> l
15 + 96 = 111 --> o

23 + 96 = 119 --> w
15 + 96 = 111 --> o
18 + 96 = 114 --> r
12 + 96 = 108 --> l
4  + 96 = 100 --> d

الرئيسي هو فئة عشوائية شيدت مع البذور نفسها سوف تولد نفس نمط الأرقام في كل مرة.


عندما يتم إنشاء مثيل java.util.Random مع معلمة بذرة محددة (في هذه الحالة -229985452 أو -147909649 ) ، فإنه يتبع خوارزمية إنشاء الأرقام العشوائية التي تبدأ بقيمة تلك البذور.

كل Random شيدت مع البذور نفسها ستولد نفس نمط الأرقام في كل مرة.


معظم مولدات الأرقام العشوائية هي ، في الواقع ، "عشوائية زائفة". هم مولدات Congruential الخطية ، أو LCGs ( http://en.wikipedia.org/wiki/Linear_congruential_generator )

LCGs يمكن التنبؤ بها تماما في ضوء البذور الثابتة. بشكل أساسي ، استخدم بذرة تمنحك الحرف الأول ، ثم اكتب أحد التطبيقات التي تستمر في إنشاء int (char) التالي حتى تصل إلى الحرف التالي في السلسلة المستهدفة وتكتب عدد المرات التي يجب عليك فيها استدعاء LCG. استمر حتى يتم إنشاء كل حرف.


كنت مفتون بذلك ، ركضت هذا مولد كلمة عشوائية على قائمة الكلمات القاموس. النطاق: 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 

مستمد من جواب دينيس تولسكي ، هذه الطريقة تولد البذور.

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;
            }

        }

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

من Java docs ، هذه ميزة مقصودة عند تحديد قيمة seed لفئة Random.

إذا تم إنشاء حالتين عشوائيتين باستخدام نفس البذرة ، ويتم إجراء نفس تسلسل استدعاءات الأسلوب لكل منهما ، فسوف ينتجان ويعيدان تسلسلات متشابهة للأرقام. من أجل ضمان هذه الخاصية ، يتم تحديد خوارزميات معينة للفئة عشوائية. يجب أن تستخدم تطبيقات Java جميع الخوارزميات الموضحة هنا للفئة Random ، من أجل قابلية شفرة Java البرمجية المطلقة.

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

على الرغم من الغريب ، قد تعتقد أن هناك مشاكل أمنية ضمنية في وجود أرقام "عشوائية" يمكن التنبؤ بها.


إنها عن "البذور". البذور نفسها تعطي نفس النتيجة.


دائمًا ما يعيد العائد التسلسل نفسه. يتم استخدامه لخلط المصفوفات والعمليات الأخرى كبديلة.

للحصول على تسلسلات مختلفة ، من الضروري تهيئة التسلسل في موضع ما ، يسمى "seed".

يحصل randomSting على الرقم العشوائي في الموضع i (البذور = -229985452) للتسلسل "العشوائي". ثم يستخدم رمز ASCII للحرف 27 التالي في التسلسل بعد موضع البذور حتى تساوي هذه القيمة إلى 0. هذا إرجاع "hello". نفس العملية تتم لـ "العالم".

أعتقد أن الكود لم يعمل لأي كلمات أخرى. الرجل المبرمج الذي يعرف التسلسل العشوائي بشكل جيد.

إنه رمز مهيب عظيم جدًا!


نظرًا لأن تعدد مؤشرات الترابط سهل للغاية مع Java ، فإليك متغيرًا يبحث عن البذور باستخدام جميع النوى المتوفرة: http://ideone.com/ROhmTA

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class SeedFinder {

  static class SearchTask implements Callable<Long> {

    private final char[] goal;
    private final long start, step;

    public SearchTask(final String goal, final long offset, final long step) {
      final char[] goalAsArray = goal.toCharArray();
      this.goal = new char[goalAsArray.length + 1];
      System.arraycopy(goalAsArray, 0, this.goal, 0, goalAsArray.length);
      this.start = Long.MIN_VALUE + offset;
      this.step = step;
    }

    @Override
    public Long call() throws Exception {
      final long LIMIT = Long.MAX_VALUE - this.step;
      final Random random = new Random();
      int position, rnd;
      long seed = this.start;

      while ((Thread.interrupted() == false) && (seed < LIMIT)) {
        random.setSeed(seed);
        position = 0;
        rnd = random.nextInt(27);
        while (((rnd == 0) && (this.goal[position] == 0))
                || ((char) ('`' + rnd) == this.goal[position])) {
          ++position;
          if (position == this.goal.length) {
            return seed;
          }
          rnd = random.nextInt(27);
        }
        seed += this.step;
      }

      throw new Exception("No match found");
    }
  }

  public static void main(String[] args) {
    final String GOAL = "hello".toLowerCase();
    final int NUM_CORES = Runtime.getRuntime().availableProcessors();

    final ArrayList<SearchTask> tasks = new ArrayList<>(NUM_CORES);
    for (int i = 0; i < NUM_CORES; ++i) {
      tasks.add(new SearchTask(GOAL, i, NUM_CORES));
    }

    final ExecutorService executor = Executors.newFixedThreadPool(NUM_CORES, new ThreadFactory() {

      @Override
      public Thread newThread(Runnable r) {
        final Thread result = new Thread(r);
        result.setPriority(Thread.MIN_PRIORITY); // make sure we do not block more important tasks
        result.setDaemon(false);
        return result;
      }
    });
    try {
      final Long result = executor.invokeAny(tasks);
      System.out.println("Seed for \"" + GOAL + "\" found: " + result);
    } catch (Exception ex) {
      System.err.println("Calculation failed: " + ex);
    } finally {
      executor.shutdownNow();
    }
  }
}

لقد قام الجميع هنا بعمل رائع لشرح كيفية عمل الشفرة وإظهار كيفية بناء الأمثلة الخاصة بك ، ولكن إليك هنا معلومات نظرية توضح السبب الذي يجعلنا نتوقع بشكل معقول وجود حل موجود في نهاية المطاف والذي سيجده البحث عن القوة الغاشمة في نهاية المطاف.

تشكل الأحرف الصغيرة المختلفة البالغ عددها 26 حرفًا أبجديًا Σ . للسماح بتوليد كلمات ذات أطوال مختلفة ، نضيف أيضًا رمز فاصل للحصول على أبجدية موسعة Σ' := Σ ∪ {⊥} .

دع α يكون رمزًا و X متغيرًا عشوائيًا موزَّعًا بشكل منتظم على Σ' . Σ' . ويحصل على احتمال الحصول على هذا الرمز ، P(X = α) ، ومحتوى المعلومات الخاص به ، I(α) ، بواسطة:

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

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

للحصول على كلمة ω ∈ Σ* ⊥- المنتهية ω' := ω · ⊥ ∈ (Σ')* ، لدينا

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

بما أن مولد الرقم العشوائي الزائف (PRNG) تمت تهيئته ببذور 32 بت ، يمكننا أن نتوقع معظم كلمات الطول تصل إلى

λ = الكلمة [32 / log₂ (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


SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')

شيء من Devise





java string random