Skip to content

Commit 71a61c5

Browse files
authored
examples: add a Lorem Ipsum Generator (#26036)
1 parent 7544034 commit 71a61c5

File tree

1 file changed

+166
-0
lines changed

1 file changed

+166
-0
lines changed

examples/lorem.v

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import rand
2+
import strings
3+
import flag
4+
import os
5+
6+
// Features:
7+
// - All parameters configurable via flags
8+
// - Reproducible output via --seed
9+
// - No invalid punctuation sequences
10+
// - Em-dashes never near sentence edges
11+
12+
// ---------------- Configuration ----------------
13+
14+
pub struct LoremCfg {
15+
paragraphs int = 3
16+
words_per_sentence int = 10
17+
sentences_per_paragraph int = 5
18+
commas_per_sentence int = 2
19+
seed int
20+
}
21+
22+
// ---------------- Generator --------------------
23+
24+
pub fn generate_lorem(cfg LoremCfg) string {
25+
lorem_words := ('lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod ' +
26+
'tempor incididunt ut labore et dolore magna aliqua enim ad minim veniam ' +
27+
'quis nostrud exercitation ullamco laboris nisi aliquip ex ea').split(' ')
28+
29+
comma_marks := ['‚', '،', ',', ',', '﹐']
30+
sentence_marks := ['.', '…', '。', '!', '?']
31+
32+
if cfg.seed != 0 {
33+
rand.seed([u32(cfg.seed), u32(cfg.seed ^ 0x9e3779b9)])
34+
}
35+
36+
mut out := strings.new_builder(2048)
37+
38+
for p in 0 .. cfg.paragraphs {
39+
sentence_count := vary(cfg.sentences_per_paragraph)
40+
41+
for _ in 0 .. sentence_count {
42+
word_count := vary(cfg.words_per_sentence)
43+
44+
expected_breaks := if cfg.words_per_sentence > 0 {
45+
(word_count * cfg.commas_per_sentence) / cfg.words_per_sentence
46+
} else {
47+
0
48+
}
49+
50+
mut inserted_breaks := 0
51+
mut last_had_splitter := false
52+
min_dash_offset := 2
53+
54+
for w in 0 .. word_count {
55+
word := lorem_words[rand.intn(lorem_words.len) or { 0 }]
56+
57+
if w == 0 {
58+
out.write_string(capitalize(word))
59+
} else {
60+
out.write_string(' ')
61+
out.write_string(word)
62+
}
63+
64+
is_last := w == word_count - 1
65+
66+
// ---- Clause splitters
67+
if !is_last && inserted_breaks < expected_breaks
68+
&& (w + 1) * expected_breaks / word_count > inserted_breaks {
69+
use_strong := rand.intn(6) or { 0 } == 0
70+
71+
if use_strong {
72+
if w >= min_dash_offset && w < word_count - 1 - min_dash_offset {
73+
out.write_string('—')
74+
} else {
75+
out.write_string(';')
76+
}
77+
} else {
78+
out.write_string(comma_marks[rand.intn(comma_marks.len) or { 0 }])
79+
}
80+
81+
inserted_breaks++
82+
last_had_splitter = true
83+
continue
84+
}
85+
86+
last_had_splitter = false
87+
88+
// ---- Sentence terminator
89+
if is_last {
90+
if last_had_splitter {
91+
out.write_string('.')
92+
} else {
93+
out.write_string(sentence_marks[rand.intn(sentence_marks.len) or { 0 }])
94+
}
95+
}
96+
}
97+
98+
out.write_string(' ')
99+
}
100+
101+
if p < cfg.paragraphs - 1 {
102+
out.write_string('\n\n')
103+
}
104+
}
105+
106+
return out.str()
107+
}
108+
109+
// ---------------- Utilities --------------------
110+
111+
fn vary(base int) int {
112+
if base <= 1 {
113+
return 1
114+
}
115+
delta := base / 5
116+
r := rand.intn(delta * 2 + 1) or { 0 }
117+
return clamp(base + r - delta, 1, 10_000)
118+
}
119+
120+
fn capitalize(s string) string {
121+
if s.len == 0 {
122+
return s
123+
}
124+
return s[..1].to_upper() + s[1..]
125+
}
126+
127+
fn clamp(v int, min int, max int) int {
128+
if v < min {
129+
return min
130+
}
131+
if v > max {
132+
return max
133+
}
134+
return v
135+
}
136+
137+
// ---------------- CLI --------------------------
138+
139+
fn main() {
140+
mut fp := flag.new_flag_parser(os.args)
141+
fp.application('lorem')
142+
fp.description('Lorem Ipsum generator with structured punctuation')
143+
fp.skip_executable()
144+
145+
paragraphs := fp.int('paragraphs', `p`, 3, 'number of paragraphs')
146+
words := fp.int('words', `w`, 10, 'approx words per sentence')
147+
sentences := fp.int('sentences', `s`, 5, 'approx sentences per paragraph')
148+
commas := fp.int('commas', `c`, 2, 'comma density per sentence')
149+
seed := fp.int('seed', 0, 0, 'RNG seed (0 = deterministic default)')
150+
151+
fp.finalize() or {
152+
eprintln(err)
153+
println(fp.usage())
154+
return
155+
}
156+
157+
cfg := LoremCfg{
158+
paragraphs: paragraphs
159+
words_per_sentence: words
160+
sentences_per_paragraph: sentences
161+
commas_per_sentence: commas
162+
seed: seed
163+
}
164+
165+
println(generate_lorem(cfg))
166+
}

0 commit comments

Comments
 (0)