Skip to content

Commit fa1d828

Browse files
committed
First stable release
1 parent 1a79064 commit fa1d828

File tree

7 files changed

+420
-0
lines changed

7 files changed

+420
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/vendor/

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,51 @@
11
# php-text-generator
22
Fast SEO text generator on a mask.
3+
4+
Written in PHP. I do not use regular expressions and the fastest.
5+
I covered tests and simple! Supporting recursive text generation rules.
6+
It supports multiple encodings.
7+
8+
This package implements the functionality of a similar package for Go Lang – [text-generator](https://github.com/liderman/text-generator).
9+
10+
Installation
11+
------------
12+
13+
composer install liderman/php-text-generator
14+
15+
Usage
16+
-----
17+
An example of a simple template text generation:
18+
```php
19+
$textGen = new TextGenerator();
20+
echo $textGen->generate("Good {morning|day}!");
21+
// Displays: Good morning!
22+
// or
23+
// Good day!
24+
```
25+
26+
An example of a complex generation template text:
27+
```php
28+
$textGen = new TextGenerator();
29+
echo $textGen->generate("{Good {morning|evening|day}|Goodnight|Hello}, {friend|brother}! {How are you|What's new with you}?");
30+
// Displays: Good morning, friend! How are you?
31+
// or
32+
// Good day, brother! What's new with you?
33+
// or
34+
// Hello, friend! How are you?
35+
// ...
36+
```
37+
38+
Features
39+
--------
40+
* It supports multiple encodings
41+
* Supporting recursive text generation rules
42+
* Fast! Does not use regular expressions
43+
* Easy wrapping thanks to the integrated interface
44+
* Covered tests
45+
* Written by PSR standards and 100% covered with documentation (PHP-Doc)
46+
47+
Requirements
48+
-----------
49+
50+
* PHP >= 5.5.9.
51+

Tests/TextGeneratorTest.php

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the TextGenerator package.
5+
*
6+
* (c) Konstantin Osipov <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Liderman\TextGenerator\Tests;
13+
14+
use Liderman\TextGenerator\TextGenerator;
15+
16+
class TextGeneratorTest extends \PHPUnit_Framework_TestCase
17+
{
18+
public function testGenerator()
19+
{
20+
$textGen = new TextGenerator();
21+
22+
$this->assertEquals(
23+
$textGen->generate("{aaa|aaa}"),
24+
'aaa'
25+
);
26+
27+
$this->assertEquals(
28+
$textGen->generate("{aaa|aaa} {bbb|bbb}"),
29+
'aaa bbb'
30+
);
31+
32+
$this->assertEquals(
33+
$textGen->generate("aaa {bbb|bbb} ccc {ddd|ddd} eee"),
34+
'aaa bbb ccc ddd eee'
35+
);
36+
37+
$this->assertEquals(
38+
$textGen->generate("{{aaa|aaa}|{aaa|aaa}}"),
39+
'aaa'
40+
);
41+
42+
$this->assertEquals(
43+
$textGen->generate("aaa{bbb{ccc|ccc}ddd|bbb{ccc|ccc}ddd}eee"),
44+
'aaabbbcccdddeee'
45+
);
46+
47+
$this->assertEquals(
48+
$textGen->generate("aaa"),
49+
'aaa'
50+
);
51+
52+
$this->assertEquals(
53+
$textGen->generate("{}"),
54+
''
55+
);
56+
57+
$this->assertEquals(
58+
$textGen->generate("{|}"),
59+
''
60+
);
61+
}
62+
63+
public function testCustomConfig()
64+
{
65+
$textGen = new TextGenerator();
66+
$textGen->setStartTag('[');
67+
$textGen->setEndTag(']');
68+
$textGen->setSeparator('!');
69+
70+
$this->assertEquals(
71+
$textGen->generate("[aaa!aaa]"),
72+
'aaa'
73+
);
74+
}
75+
76+
public function testConstructor()
77+
{
78+
$textGen = new TextGenerator('<', '>', '!');
79+
80+
$this->assertEquals(
81+
$textGen->generate("<aaa!aaa>"),
82+
'aaa'
83+
);
84+
}
85+
}

TextGenerator.php

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the TextGenerator package.
5+
*
6+
* (c) Konstantin Osipov <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Liderman\TextGenerator;
13+
14+
/**
15+
* Fast SEO text generator on a mask.
16+
*
17+
* @package Liderman\TextGenerator
18+
*/
19+
class TextGenerator implements TextGeneratorInterface
20+
{
21+
/**
22+
* Default start tag
23+
*/
24+
const DEF_START_TAG = '{';
25+
26+
/**
27+
* Default end tag
28+
*/
29+
const DEF_END_TAG = '}';
30+
31+
/**
32+
* Default separator
33+
*/
34+
const DEF_SEPARATOR = '|';
35+
36+
/**
37+
* @var string Start tag
38+
*/
39+
private $startTag;
40+
41+
/**
42+
* @var string End tag
43+
*/
44+
private $endTag;
45+
46+
/**
47+
* @var string Separator
48+
*/
49+
private $separator;
50+
51+
/**
52+
* @var string Encoding
53+
*/
54+
private $encoding = 'UTF-8';
55+
56+
/**
57+
* Constructor.
58+
*
59+
* @param string $startTag Start tag
60+
* @param string $endTag End tag
61+
* @param string $separator Separator
62+
*/
63+
public function __construct(
64+
$startTag = self::DEF_START_TAG,
65+
$endTag = self::DEF_END_TAG,
66+
$separator = self::DEF_SEPARATOR
67+
) {
68+
$this->setStartTag($startTag);
69+
$this->setEndTag($endTag);
70+
$this->setSeparator($separator);
71+
}
72+
73+
/**
74+
* Set start tag.
75+
*
76+
* @param string $startTag Start tag
77+
*/
78+
public function setStartTag($startTag = self::DEF_START_TAG)
79+
{
80+
$this->startTag = $startTag;
81+
}
82+
83+
/**
84+
* Set end tag.
85+
*
86+
* @param string $endTag End tag
87+
*/
88+
public function setEndTag($endTag = self::DEF_END_TAG)
89+
{
90+
$this->endTag = $endTag;
91+
}
92+
93+
/**
94+
* Set separator.
95+
*
96+
* @param string $separator Separator
97+
*/
98+
public function setSeparator($separator = self::DEF_SEPARATOR)
99+
{
100+
$this->separator = $separator;
101+
}
102+
103+
/**
104+
* Set encoding.
105+
*
106+
* @param string $encoding Encoding
107+
*/
108+
public function setEncoding($encoding = 'UTF-8')
109+
{
110+
$this->encoding = $encoding;
111+
}
112+
113+
/**
114+
* @inheritdoc
115+
*/
116+
public function generate($text)
117+
{
118+
$startSafePos = 0;
119+
$startPos = 0;
120+
$endPos = 0;
121+
$openLevel = 0;
122+
$isFind = false;
123+
$result = '';
124+
$textLen = mb_strlen($text, $this->encoding);
125+
for ($i = 0; $i < $textLen; $i++) {
126+
if (mb_substr($text, $i, 1, $this->encoding) === $this->startTag) {
127+
if ($openLevel === 0) {
128+
$startPos = $i;
129+
$result .= mb_substr($text, $startSafePos, $startPos - $startSafePos, $this->encoding);
130+
}
131+
132+
$openLevel++;
133+
continue;
134+
}
135+
136+
if (mb_substr($text, $i, 1, $this->encoding) === $this->endTag) {
137+
$openLevel--;
138+
139+
if ($openLevel === 0) {
140+
$isFind = true;
141+
$endPos = $i;
142+
143+
$startSafePos = $i + 1;
144+
145+
$result .= $this->generate(
146+
$this->getRandomPart(
147+
mb_substr($text, $startPos + 1, $endPos - ($startPos + 1), $this->encoding)
148+
)
149+
);
150+
151+
continue;
152+
}
153+
}
154+
}
155+
156+
if ($isFind === false) {
157+
return $text;
158+
}
159+
160+
return $result . mb_substr($text, $endPos + 1, null, $this->encoding);
161+
}
162+
163+
/**
164+
* Returns a random part of text.
165+
*
166+
* @param string $text Text
167+
*
168+
* @return string Random part of text
169+
*/
170+
private function getRandomPart($text)
171+
{
172+
$openLevel = 0;
173+
$lastPos = 0;
174+
$isIgnore = false;
175+
$parts = [];
176+
for ($i = 0; $i < mb_strlen($text, $this->encoding); $i++) {
177+
$currentChar = mb_substr($text, $i, 1, $this->encoding);
178+
if ($currentChar === $this->startTag) {
179+
$openLevel++;
180+
$isIgnore = true;
181+
continue;
182+
}
183+
184+
if ($currentChar === $this->endTag) {
185+
$openLevel--;
186+
if ($openLevel === 0) {
187+
$isIgnore = false;
188+
}
189+
190+
continue;
191+
}
192+
193+
if ($isIgnore === true) {
194+
continue;
195+
}
196+
197+
if ($currentChar === $this->separator) {
198+
$parts[] = mb_substr($text, $lastPos, $i, $this->encoding);
199+
$lastPos = $i + 1;
200+
}
201+
}
202+
203+
$parts[] = mb_substr($text, $lastPos, null, $this->encoding);
204+
205+
return $parts[array_rand($parts)];
206+
}
207+
}

TextGeneratorInterface.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the TextGenerator package.
5+
*
6+
* (c) Konstantin Osipov <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Liderman\TextGenerator;
13+
14+
/**
15+
* Interface TextGeneratorInterface.
16+
*
17+
* @package Liderman\TextGenerator
18+
*/
19+
interface TextGeneratorInterface
20+
{
21+
/**
22+
* Generates and returns a new text.
23+
*
24+
* Use the rules for generating a plurality of texts
25+
* Example mask: `Good {morning|day}!`
26+
*
27+
* @param string $text Text template
28+
*
29+
* @return string Result text
30+
*/
31+
public function generate($text);
32+
}

0 commit comments

Comments
 (0)