Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add isFemale parameter #75

Merged
merged 1 commit into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions docs/classes/ArPHP-I18N-Arabic.html
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,6 @@ <h4 class="phpdocumentor-element__name" id="method_ar2en">
<code class="phpdocumentor-code phpdocumentor-signature ">
<span class="phpdocumentor-signature__visibility">public</span>
<span class="phpdocumentor-signature__name">ar2en</span><span>(</span><span class="phpdocumentor-signature__argument"><span class="phpdocumentor-signature__argument__return-type">string&nbsp;</span><span class="phpdocumentor-signature__argument__name">$string</span></span><span class="phpdocumentor-signature__argument"><span>[</span><span>, </span><span class="phpdocumentor-signature__argument__return-type">string&nbsp;</span><span class="phpdocumentor-signature__argument__name">$standard</span><span> = </span><span class="phpdocumentor-signature__argument__default-value">&#039;UNGEGN&#039;</span><span> ]</span></span><span>)</span><span> : </span><span class="phpdocumentor-signature__response_type">string</span></code>

<section class="phpdocumentor-description"></section>

<h5 class="phpdocumentor-argument-list__heading">Parameters</h5>
Expand Down Expand Up @@ -1061,7 +1060,7 @@ <h4 class="phpdocumentor-element__name" id="method_arPlural">

<code class="phpdocumentor-code phpdocumentor-signature ">
<span class="phpdocumentor-signature__visibility">public</span>
<span class="phpdocumentor-signature__name">arPlural</span><span>(</span><span class="phpdocumentor-signature__argument"><span class="phpdocumentor-signature__argument__return-type">string&nbsp;</span><span class="phpdocumentor-signature__argument__name">$singular</span></span><span class="phpdocumentor-signature__argument"><span>, </span><span class="phpdocumentor-signature__argument__return-type">int&nbsp;</span><span class="phpdocumentor-signature__argument__name">$count</span></span><span class="phpdocumentor-signature__argument"><span>[</span><span>, </span><span class="phpdocumentor-signature__argument__return-type">string&nbsp;</span><span class="phpdocumentor-signature__argument__name">$plural2</span><span> = </span><span class="phpdocumentor-signature__argument__default-value">null</span><span> ]</span></span><span class="phpdocumentor-signature__argument"><span>[</span><span>, </span><span class="phpdocumentor-signature__argument__return-type">string&nbsp;</span><span class="phpdocumentor-signature__argument__name">$plural3</span><span> = </span><span class="phpdocumentor-signature__argument__default-value">null</span><span> ]</span></span><span class="phpdocumentor-signature__argument"><span>[</span><span>, </span><span class="phpdocumentor-signature__argument__return-type">string&nbsp;</span><span class="phpdocumentor-signature__argument__name">$plural4</span><span> = </span><span class="phpdocumentor-signature__argument__default-value">null</span><span> ]</span></span><span>)</span><span> : </span><span class="phpdocumentor-signature__response_type">string</span></code>
<span class="phpdocumentor-signature__name">arPlural</span><span>(</span> <span class="phpdocumentor-signature__argument"> <span class="phpdocumentor-signature__argument__return-type">string&nbsp;</span> <span class="phpdocumentor-signature__argument__name">$singular</span> </span> <span class="phpdocumentor-signature__argument"> <span>, </span> <span class="phpdocumentor-signature__argument__return-type">int&nbsp;</span> <span class="phpdocumentor-signature__argument__name">$count</span> </span> <span class="phpdocumentor-signature__argument"> <span>[</span> <span>, </span> <span class="phpdocumentor-signature__argument__return-type">string&nbsp;</span> <span class="phpdocumentor-signature__argument__name">$plural2</span> <span> = </span> <span class="phpdocumentor-signature__argument__default-value">null</span> <span> ]</span> </span> <span class="phpdocumentor-signature__argument"> <span>[</span> <span>, </span> <span class="phpdocumentor-signature__argument__return-type">string&nbsp;</span> <span class="phpdocumentor-signature__argument__name">$plural3</span> <span> = </span> <span class="phpdocumentor-signature__argument__default-value">null</span> <span> ]</span> </span> <span class="phpdocumentor-signature__argument"> <span>[</span> <span>, </span> <span class="phpdocumentor-signature__argument__return-type">string&nbsp;</span> <span class="phpdocumentor-signature__argument__name">$plural4</span> <span> = </span> <span class="phpdocumentor-signature__argument__default-value">null</span> <span> ]</span> </span> <span class="phpdocumentor-signature__argument"> <span>[</span> <span>, </span> <span class="phpdocumentor-signature__argument__return-type">bool&nbsp;</span> <span class="phpdocumentor-signature__argument__name">$nameOnly</span> <span> = </span> <span class="phpdocumentor-signature__argument__default-value">false</span> <span> ]</span> </span> <span class="phpdocumentor-signature__argument"> <span>[</span> <span>, </span> <span class="phpdocumentor-signature__argument__return-type">bool&nbsp;</span> <span class="phpdocumentor-signature__argument__name">$isFemale</span> <span> = </span> <span class="phpdocumentor-signature__argument__default-value">null</span> <span> ]</span> </span><span>)</span><span> : </span><span class="phpdocumentor-signature__response_type">string</span></code>

<section class="phpdocumentor-description"></section>

Expand Down Expand Up @@ -1123,6 +1122,16 @@ <h5 class="phpdocumentor-argument-list__heading">Parameters</h5>

</dd>

<dt class="phpdocumentor-argument-list__entry">
<span class="phpdocumentor-signature__argument__name">$isFemale</span>
: <span class="phpdocumentor-signature__argument__return-type">bool</span>
= <span class="phpdocumentor-signature__argument__default-value">null</span> </dt>
<dd class="phpdocumentor-argument-list__definition">
<section class="phpdocumentor-description"><p>$isFemale explicitly says that this word is female or not, (e.g., خطأ) is considered by the detection algorithm in the library as female, which is wrong. if we pass explicit that it is not female to fix the output.</p>
</section>

</dd>

</dl>


Expand Down
7 changes: 6 additions & 1 deletion examples/numbers.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,12 @@


$number = 4;
$text = $Arabic->arPlural('يوم', $number, nameOnly: true);
$text = $Arabic->arPlural('يوم', $number, nameOnly: true); // str_replace('%d', $number, $text) is redundant in this case

echo "<p align=center><span style='font-size: 24px; font-weight: bold; color: #0077cc; margin-right: 10px;' >$number</span> $text</p>";

$number = 1;
$text = $Arabic->arPlural('خطأ', $number, isFemale: false);
$text = str_replace('%d', $number, $text);

echo "<p align=center><span style='font-size: 24px; font-weight: bold; color: #0077cc; margin-right: 10px;' >$number</span> $text</p>";
Expand Down
62 changes: 32 additions & 30 deletions src/Arabic.php
Original file line number Diff line number Diff line change
Expand Up @@ -377,13 +377,13 @@ class Arabic

/** @var array<string> */
private $arGapPenalty = array();

/** @var float */
private $keyboardWeight = 1;

/** @var float */
private $graphicWeight = 1;

/** @var float */
private $phoneticWeight = 1;

Expand Down Expand Up @@ -414,7 +414,7 @@ public function __construct()
$this->arDialectInit();
$this->arSimilarityInit();
}

/** @return void */
private function arSpellerInit() {
$this->speller = new \ArPHP\MZK\Speller();
Expand All @@ -424,7 +424,7 @@ private function arSpellerInit() {
* Spell Check
*
* @param string $text Text input
* @return array<string>
* @return array<string>
* @author Moutaz Alkhatib <[email protected]>
*/
public function spellGetMisspelled($text) {
Expand Down Expand Up @@ -4232,13 +4232,15 @@ public function volc($olc, $codeLength = 10)
* @return string Proper plural form of the given singular form
* @author Khaled Al-Sham'aa <[email protected]>
*/
public function arPlural($singular, $count, $plural2 = null, $plural3 = null, $plural4 = null, $nameOnly = false)
public function arPlural($singular, $count, $plural2 = null, $plural3 = null, $plural4 = null, $nameOnly = false, $isFemale = null)
{
$isFemale = $isFemale === null ? $this->isFemale($singular) : $isFemale;

if ($count == 0) {
$plural = is_null($plural2) ? $this->arPluralsForms[$singular][0] : "لا $plural3";
} elseif ($count == 1 && $this->isFemale($singular)) {
} elseif ($count == 1 && $isFemale) {
$plural = is_null($plural2) ? $this->arPluralsForms[$singular][1] : "$singular واحدة";
} elseif ($count == 1 && !$this->isFemale($singular)) {
} elseif ($count == 1 && !$isFemale) {
$plural = is_null($plural2) ? $this->arPluralsForms[$singular][1] : "$singular واحد";
} elseif ($count == 2) {
$plural = is_null($plural2) ? $this->arPluralsForms[$singular][2] : $plural2;
Expand Down Expand Up @@ -4471,7 +4473,7 @@ public function arDialect($text)
}

$score = max($scoreEgyptian, $scoreLevantine, $scoreMaghrebi, $scorePeninsular);

switch ($score) {
case $scoreEgyptian:
$dialect = 'Egyptian';
Expand Down Expand Up @@ -4845,10 +4847,10 @@ private function arKeyboardSimilarity($chr1, $chr2)
// shift key status (0/1 if pressed)
$zi = $this->arKeyZ["$chr1"];
$zj = $this->arKeyZ["$chr2"];

// similarity score
$score = 0;

if ($yi == $yj && $xi == $xj) {
// the same key + shift status penalty if differ
$score = 8 - 4 * abs($zi - $zj);
Expand All @@ -4862,18 +4864,18 @@ private function arKeyboardSimilarity($chr1, $chr2)
// up or down + shift status penalty if differ
$score = 2 - 1 * abs($zi - $zj);
}

return $score;
}

private function arGraphicSimilarity($chr1, $chr2)
{
if (!array_key_exists($chr1, $this->arGraphGroup) || !array_key_exists($chr2, $this->arGraphGroup)) {
$score = 0;
} else {
$chr1Group = $this->arGraphGroup["$chr1"];
$chr2Group = $this->arGraphGroup["$chr2"];

if ($chr1 == $chr2) {
$score = 8;
} elseif ($chr1Group == $chr2Group) {
Expand All @@ -4882,10 +4884,10 @@ private function arGraphicSimilarity($chr1, $chr2)
$score = 0;
}
}

return $score;
}

private function arSoundSimilarity($chr1, $chr2)
{
if ($chr1 == $chr2) {
Expand All @@ -4895,17 +4897,17 @@ private function arSoundSimilarity($chr1, $chr2)
} else {
$chr1Group = $this->arSoundGroup["$chr1"];
$chr2Group = $this->arSoundGroup["$chr2"];

if ($chr1Group == $chr2Group) {
$score = 4;
} else {
$score = 0;
}
}

return $score;
}

// the similarity score of characters a and b (keyboard, graphic, phonetic)
private function S($chr1, $chr2)
{
Expand All @@ -4917,7 +4919,7 @@ private function S($chr1, $chr2)

return $score;
}

// gap penalty scores (for each character)
private function d($chr)
{
Expand All @@ -4926,10 +4928,10 @@ private function d($chr)
} else {
$score = 8;
}

return -1 * $score;
}

// https://en.wikipedia.org/wiki/Needleman-Wunsch_algorithm
// Needleman-Wunsch algorithm using weighted scoring matrices and gap penalty
private function arSimilarityScore($string1, $string2)
Expand All @@ -4950,36 +4952,36 @@ private function arSimilarityScore($string1, $string2)
$chr = mb_substr($string2, $j-1, 1);
$F[0][$j] = $this->d($chr) + $F[0][$j-1];
}

for ($i = 1; $i <= $max1; $i++) {
for ($j = 1; $j <= $max2; $j++) {
$A = mb_substr($string1, $i-1, 1);
$B = mb_substr($string2, $j-1, 1);

$match = $F[$i-1][$j-1] + $this->S($A, $B);
$delete = $F[$i-1][$j] + $this->d($A);
$insert = $F[$i][$j-1] + $this->d($B);

$F[$i][$j] = max($match, $delete, $insert);
}
}
$score = $F[$max1][$max2];

return $score;
}

// Calculate the similarity between two Arabic strings
public function similar_text($string1, $string2, &$percent = null)
{
$score = $this->arSimilarityScore($string1, $string2);
$score1 = $this->arSimilarityScore($string1, $string1);
$score2 = $this->arSimilarityScore($string2, $string2);

$percent = 100 * $score / max($score1, $score2);

return $score/8;
}

public function setSimilarityWeight($source, $value = 1)
{
switch ($source) {
Expand Down
6 changes: 5 additions & 1 deletion tests/ArabicTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1105,11 +1105,15 @@ public function testArabicPluralForms(): void
$actual[] = str_replace('%d', $number, $text);

$number = 7;

$expected[] = 'أيام';
$text = $Arabic->arPlural('يوم', $number, nameOnly: true);
$actual[] = $text; // str_replace('%d', $number, $text) is redundant in this case

$number = 1;
$expected[] = 'خطأ واحد';
$text = $Arabic->arPlural('خطأ', 1, 'خطآن', 'أخطاء', 'خطأ', isFemale: false);
$actual[] = str_replace('%d', $number, $text);

$this->assertEquals($actual, $expected);
}

Expand Down