1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2024-09-28 14:30:51 +00:00

Xomw: Add commafy

This commit is contained in:
gnosygnu 2017-04-18 21:38:55 -04:00
parent 80f572a06c
commit fb934457f9
7 changed files with 459 additions and 183 deletions

View File

@ -302,6 +302,11 @@ public class Bry_ {
for (int i = src_bgn; i < src_end; i++)
trg[i + trg_adj] = src[i];
}
public static void Copy_by_pos_reversed(byte[] src, int src_bgn, int src_end, byte[] trg, int trg_bgn) {
int len = src_end - src_bgn;
for (int i = 0; i < len; i++)
trg[trg_bgn + i] = src[src_end - i - 1];
}
private static void Copy_by_len(byte[] src, int src_bgn, int src_len, byte[] trg, int trg_bgn) {
for (int i = 0; i < src_len; i++)
trg[i + trg_bgn] = src[i + src_bgn];

View File

@ -93,6 +93,15 @@ public class Bry_bfr {
bfr_len += len;
return this;
}
public Bry_bfr Add_reverse_mid(byte[] val, int bgn, int end) {
int len = end - bgn;
if (len < 0) throw Err_.new_wo_type("negative len", "bgn", bgn, "end", end, "excerpt", String_.new_u8__by_len(val, bgn, bgn + 16)); // NOTE: check for invalid end < bgn, else difficult to debug errors later; DATE:2014-05-11
if (bfr_len + len > bfr_max) Resize((bfr_max + len) * 2);
Bry_.Copy_by_pos_reversed(val, bgn, end, bfr, bfr_len);
// Array_.Copy_to(val, bgn, bfr, bfr_len, len);
bfr_len += len;
return this;
}
public Bry_bfr Add_mid_w_swap(byte[] val, int bgn, int end, byte swap_src, byte swap_trg) {
int len = end - bgn;
if (len < 0) throw Err_.new_wo_type("negative len", "bgn", bgn, "end", end, "excerpt", String_.new_u8__by_len(val, bgn, bgn + 16)); // NOTE: check for invalid end < bgn, else difficult to debug errors later; DATE:2014-05-11
@ -589,6 +598,16 @@ public class Bry_bfr {
this.Mkr_rls();
return rv;
}
public byte[] To_reversed_bry_and_clear() {
int len = this.Len();
byte[] rv = new byte[len];
for (int i = 0; i < len; i++) {
rv[len - i - 1] = bfr[i];
}
this.Clear();
if (reset > 0) Reset_if_gt(reset);
return rv;
}
public String To_str() {return String_.new_u8(To_bry());}
public String To_str_by_pos(int bgn, int end) {return String_.new_u8(To_bry(), bgn, end);}
public String To_str_and_clear() {return String_.new_u8(To_bry_and_clear());}

View File

@ -75,55 +75,3 @@ public class Xoa_css_extractor_basic_tst {
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/xowa_common.css", "failover");
}
}
class Xoa_css_extractor_fxt {
public void Clear() {
Io_mgr.Instance.InitEngine_mem();
Gfo_usr_dlg usr_dlg = Gfo_usr_dlg_.Test();
css_installer = new Xoa_css_extractor();
css_installer.Download_xrg().Trg_engine_key_(IoEngine_.MemKey);
css_installer
.Usr_dlg_(usr_dlg)
.Wiki_domain_(Bry_.new_a7("en.wikipedia.org"))
.Protocol_prefix_("mem/http/")
.Mainpage_url_("mem/http/en.wikipedia.org")
.Failover_dir_(Io_url_.new_any_("mem/xowa/bin/any/html/xowa/import/")) // "mem/xowa/user/anonymous/wiki/home/html/"
.Wiki_html_dir_(Io_url_.new_any_("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/"))
;
page_fetcher = new Xow_page_fetcher_test();
css_installer.Page_fetcher_(page_fetcher);
Xoa_css_img_downloader css_img_downloader = new Xoa_css_img_downloader();
css_img_downloader.Ctor(usr_dlg, new Xof_download_wkr_test(), Bry_.new_a7("mem/http/"));
css_installer.Css_img_downloader_(css_img_downloader);
} private Xow_page_fetcher_test page_fetcher;
public Xoa_css_extractor Css_installer() {return css_installer;} private Xoa_css_extractor css_installer;
public void Init_page(int ns_id, String ttl, String text) {
page_fetcher.Add(ns_id, Bry_.new_a7(ttl), Bry_.new_a7(text));
}
public void Init_fil_empty(String url) {Init_fil(url, "");}
public void Init_fil(String url, String text) {Io_mgr.Instance.SaveFilStr(url, text);}
public void Test_fil(String url, String expd) {Tfds.Eq_str_lines(expd, Io_mgr.Instance.LoadFilStr(Io_url_.new_any_(url)));}
public void Exec_logo_setup() {
css_installer.Mainpage_download();
css_installer.Logo_setup();
}
public void Exec_css_common_setup() {
css_installer.Mainpage_download();
css_installer.Css_common_setup();
}
public void Exec_css_wiki_setup() {css_installer.Css_wiki_setup();}
public void Exec_css_mainpage_setup() {
css_installer.Mainpage_download();
css_installer.Css_scrape_setup();
}
public static String Main_page_html = String_.Concat_lines_nl
( "<html>"
, " <head>"
, " <link rel=\"stylesheet\" href=\"www/a&amp;0%7Cb%2Cc\" />"
, " <link rel=\"stylesheet\" href=\"www/a&amp;1%7Cb%2Cc\" />"
, " </head>"
, " <body>"
, " <div id=\"p-logo\" role=\"banner\"><a style=\"background-image: url(wiki.png);\""
, " </body>"
, "</html>"
);
}

View File

@ -0,0 +1,71 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import gplx.core.ios.*;
import gplx.xowa.wikis.data.fetchers.*;
import gplx.xowa.files.downloads.*;
public class Xoa_css_extractor_fxt {
public void Clear() {
Io_mgr.Instance.InitEngine_mem();
Gfo_usr_dlg usr_dlg = Gfo_usr_dlg_.Test();
css_installer = new Xoa_css_extractor();
css_installer.Download_xrg().Trg_engine_key_(IoEngine_.MemKey);
css_installer
.Usr_dlg_(usr_dlg)
.Wiki_domain_(Bry_.new_a7("en.wikipedia.org"))
.Protocol_prefix_("mem/http/")
.Mainpage_url_("mem/http/en.wikipedia.org")
.Failover_dir_(Io_url_.new_any_("mem/xowa/bin/any/html/xowa/import/")) // "mem/xowa/user/anonymous/wiki/home/html/"
.Wiki_html_dir_(Io_url_.new_any_("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/"))
;
page_fetcher = new Xow_page_fetcher_test();
css_installer.Page_fetcher_(page_fetcher);
Xoa_css_img_downloader css_img_downloader = new Xoa_css_img_downloader();
css_img_downloader.Ctor(usr_dlg, new Xof_download_wkr_test(), Bry_.new_a7("mem/http/"));
css_installer.Css_img_downloader_(css_img_downloader);
} private Xow_page_fetcher_test page_fetcher;
public Xoa_css_extractor Css_installer() {return css_installer;} private Xoa_css_extractor css_installer;
public void Init_page(int ns_id, String ttl, String text) {
page_fetcher.Add(ns_id, Bry_.new_a7(ttl), Bry_.new_a7(text));
}
public void Init_fil_empty(String url) {Init_fil(url, "");}
public void Init_fil(String url, String text) {Io_mgr.Instance.SaveFilStr(url, text);}
public void Test_fil(String url, String expd) {Tfds.Eq_str_lines(expd, Io_mgr.Instance.LoadFilStr(Io_url_.new_any_(url)));}
public void Exec_logo_setup() {
css_installer.Mainpage_download();
css_installer.Logo_setup();
}
public void Exec_css_common_setup() {
css_installer.Mainpage_download();
css_installer.Css_common_setup();
}
public void Exec_css_wiki_setup() {css_installer.Css_wiki_setup();}
public void Exec_css_mainpage_setup() {
css_installer.Mainpage_download();
css_installer.Css_scrape_setup();
}
public static String Main_page_html = String_.Concat_lines_nl
( "<html>"
, " <head>"
, " <link rel=\"stylesheet\" href=\"www/a&amp;0%7Cb%2Cc\" />"
, " <link rel=\"stylesheet\" href=\"www/a&amp;1%7Cb%2Cc\" />"
, " </head>"
, " <body>"
, " <div id=\"p-logo\" role=\"banner\"><a style=\"background-image: url(wiki.png);\""
, " </body>"
, "</html>"
);
}

View File

@ -1141,6 +1141,7 @@ public class XomwMessage {
case XomwMessagePrm.Tid__num:
// Replace number prmsVar always in before step for now.
// No support for combined raw and num prmsVar
// rv.Set(PRM_TID_BEFORE, this.getLanguage().formatNum((XomwMessagePrm_num)prm).num);
// return [PRM_TID_BEFORE, this.getLanguage()->formatNum($param['num']) ];
break;
case XomwMessagePrm.Tid__duration:

View File

@ -15,6 +15,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.languages; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*;
import gplx.xowa.mediawiki.includes.*;
import gplx.core.primitives.*;
import gplx.xowa.langs.*;
public class XomwLanguage {
public Xol_lang_itm XoLang() {return xoLang;} private Xol_lang_itm xoLang = null;
@ -34,6 +35,9 @@ public class XomwLanguage {
// /** @var array|null */
private XomwNamespacesById namespaceNames;
private XomwNamespacesByName mNamespaceIds, namespaceAliases;
private byte[] digitGroupingPattern = null;
private final List_adp tmp_matches = List_adp_.New();
private final Bry_bfr tmp_commafy = Bry_bfr_.New();
// /**
// * ReplacementArray Object caches
@ -278,7 +282,7 @@ public class XomwLanguage {
// return false;
// }
//
// if ($code === 'qqq') {
// if ($code == 'qqq') {
// return false;
// }
//
@ -364,7 +368,7 @@ public class XomwLanguage {
// // see bugs T39564, T39587, T38938
// $cache[$code] =
// // Protect against path traversal
// strcspn($code, ":/\\\000&<>'\"") === strlen($code)
// strcspn($code, ":/\\\000&<>'\"") == strlen($code)
// && !preg_match(MediaWikiTitleCodec::getTitleInvalidRegex(), $code);
// }
// return $cache[$code];
@ -411,7 +415,7 @@ public class XomwLanguage {
// }
//
// if (isset(MediaWiki\Languages\Data\Names::$names[$tag])
// || self::fetchLanguageName($tag, $tag) !== ''
// || self::fetchLanguageName($tag, $tag) != ''
// ) {
// return true;
// }
@ -653,7 +657,7 @@ public class XomwLanguage {
// $aliases = [];
// } else {
// foreach ($aliases as $name => $index) {
// if ($index === NS_PROJECT_TALK) {
// if ($index == NS_PROJECT_TALK) {
// unset($aliases[$name]);
// $name = this.fixVariableInNamespace($name);
// $aliases[$name] = $index;
@ -673,7 +677,7 @@ public class XomwLanguage {
// Also add converted namespace names as aliases, to avoid confusion.
// $convertedNames = [];
// foreach (this.getVariants() as $variant) {
// if ($variant === this.mCode) {
// if ($variant == this.mCode) {
// continue;
// }
// foreach (this.getNamespaces() as $ns => $_) {
@ -776,7 +780,7 @@ public class XomwLanguage {
// */
// public function getDefaultDateFormat() {
// $df = self::$dataCache->getItem(this.mCode, 'defaultDateFormat');
// if ($df === 'dmy or mdy') {
// if ($df == 'dmy or mdy') {
// global $wgAmericanDates;
// return $wgAmericanDates ? 'mdy' : 'dmy';
// } else {
@ -834,9 +838,9 @@ public class XomwLanguage {
// * @since 1.20
// */
// public static function fetchLanguageNames($inLanguage = null, $include = 'mw') {
// $cacheKey = $inLanguage === null ? 'null' : $inLanguage;
// $cacheKey = $inLanguage == null ? 'null' : $inLanguage;
// $cacheKey .= ":$include";
// if (self::$languageNameCache === null) {
// if (self::$languageNameCache == null) {
// self::$languageNameCache = new HashBagOStuff([ 'maxKeys' => 20 ]);
// }
//
@ -862,7 +866,7 @@ public class XomwLanguage {
// global $wgExtraLanguageNames;
//
// // If passed an invalid language code to use, fallback to en
// if ($inLanguage !== null && !Language::isValidCode($inLanguage)) {
// if ($inLanguage != null && !Language::isValidCode($inLanguage)) {
// $inLanguage = 'en';
// }
//
@ -877,12 +881,12 @@ public class XomwLanguage {
// foreach ($mwNames as $mwCode => $mwName) {
// # - Prefer own MediaWiki native name when not using the hook
// # - For other names just add if not added through the hook
// if ($mwCode === $inLanguage || !isset($names[$mwCode])) {
// if ($mwCode == $inLanguage || !isset($names[$mwCode])) {
// $names[$mwCode] = $mwName;
// }
// }
//
// if ($include === 'all') {
// if ($include == 'all') {
// ksort($names);
// return $names;
// }
@ -893,7 +897,7 @@ public class XomwLanguage {
// $returnMw[$coreCode] = $names[$coreCode];
// }
//
// if ($include === 'mwfile') {
// if ($include == 'mwfile') {
// $namesMwFile = [];
// # We do this using a foreach over the codes instead of a directory
// # loop so that messages files in extensions will work correctly.
@ -1160,7 +1164,7 @@ public class XomwLanguage {
// $usedHijriYear = false;
// $usedTennoYear = false;
//
// if (strlen($ts) !== 14) {
// if (strlen($ts) != 14) {
// throw new MWException(__METHOD__ . ": The timestamp $ts should have 14 characters");
// }
//
@ -1176,12 +1180,12 @@ public class XomwLanguage {
// $code .= $format[++$p];
// }
//
// if (($code === 'xi'
// || $code === 'xj'
// || $code === 'xk'
// || $code === 'xm'
// || $code === 'xo'
// || $code === 'xt')
// if (($code == 'xi'
// || $code == 'xj'
// || $code == 'xk'
// || $code == 'xm'
// || $code == 'xo'
// || $code == 'xt')
// && $p < $formatLength - 1) {
// $code .= $format[++$p];
// }
@ -1475,7 +1479,7 @@ public class XomwLanguage {
// # Quoted literal
// if ($p < $formatLength - 1) {
// $endQuote = strpos($format, '"', $p + 1);
// if ($endQuote === false) {
// if ($endQuote == false) {
// # No terminating quote, assume literal "
// $s .= '"';
// } else {
@ -1490,7 +1494,7 @@ public class XomwLanguage {
// default:
// $s .= $format[$p];
// }
// if ($num !== false) {
// if ($num != false) {
// if ($rawToggle || $raw) {
// $s .= $num;
// $raw = false;
@ -1506,7 +1510,7 @@ public class XomwLanguage {
// }
// }
//
// if ($ttl === 'unused') {
// if ($ttl == 'unused') {
// // No need to calculate the TTL, the caller wont use it anyway.
// } elseif ($usedSecond) {
// $ttl = 1;
@ -1628,7 +1632,7 @@ public class XomwLanguage {
// }
//
// // Leap years
// if ($gm > 1 && (($gy % 4 === 0 && $gy % 100 !== 0 || ($gy % 400 == 0)))) {
// if ($gm > 1 && (($gy % 4 == 0 && $gy % 100 != 0 || ($gy % 400 == 0)))) {
// $gDayNo++;
// }
//
@ -1992,7 +1996,7 @@ public class XomwLanguage {
// if (!preg_match(self::$strongDirRegex, $text, $matches)) {
// return null;
// }
// if ($matches[1] === '') {
// if ($matches[1] == '') {
// return 'rtl';
// }
// return 'ltr';
@ -2061,9 +2065,9 @@ public class XomwLanguage {
// }
//
// // Round thousands have special notations
// if ($num === 1000) {
// if ($num == 1000) {
// return "א' אלף";
// } elseif ($num % 1000 === 0) {
// } elseif ($num % 1000 == 0) {
// return $table[0][$num / 1000] . "' אלפים";
// }
//
@ -2071,7 +2075,7 @@ public class XomwLanguage {
//
// for ($pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i--) {
// if ($num >= $pow10) {
// if ($num === 15 || $num === 16) {
// if ($num == 15 || $num == 16) {
// $letters[] = $table[0][9];
// $letters[] = $table[0][$num - 9];
// $num = 0;
@ -2081,7 +2085,7 @@ public class XomwLanguage {
// (array)$table[$i][intval($num / $pow10)]
// );
//
// if ($pow10 === 1000) {
// if ($pow10 == 1000) {
// $letters[] = "'";
// }
// }
@ -2091,7 +2095,7 @@ public class XomwLanguage {
// }
//
// $preTransformLength = count($letters);
// if ($preTransformLength === 1) {
// if ($preTransformLength == 1) {
// // Add geresh (single quote) to one-letter numbers
// $letters[] = "'";
// } else {
@ -2105,7 +2109,7 @@ public class XomwLanguage {
// // Add gershayim (double quote) to multiple-letter numbers,
// // but exclude numbers with only one letter after the thousands
// // (1001-1009, 1020, 1030, 2001-2009, etc.)
// if ($letters[1] === "'" && $preTransformLength === 3) {
// if ($letters[1] == "'" && $preTransformLength == 3) {
// $letters[] = "'";
// } else {
// array_splice($letters, -1, 0, '"');
@ -2126,7 +2130,7 @@ public class XomwLanguage {
// public function userAdjust($ts, $tz = false) {
// global $wgUser, $wgLocalTZoffset;
//
// if ($tz === false) {
// if ($tz == false) {
// $tz = $wgUser->getOption('timecorrection');
// }
//
@ -2244,11 +2248,11 @@ public class XomwLanguage {
// if (!isset(this.dateFormatStrings[$type][$pref])) {
// $df = self::$dataCache->getSubitem(this.mCode, 'dateFormats', "$pref $type");
//
// if ($type === 'pretty' && $df === null) {
// if ($type == 'pretty' && $df == null) {
// $df = this.getDateFormatString('date', $pref);
// }
//
// if (!$wasDefault && $df === null) {
// if (!$wasDefault && $df == null) {
// $pref = this.getDefaultDateFormat();
// $df = self::$dataCache->getSubitem(this.mCode, 'dateFormats', "$pref $type");
// }
@ -2406,15 +2410,15 @@ public class XomwLanguage {
// private function internalUserTimeAndDate($type, $ts, User $user, array $options) {
// $ts = wfTimestamp(TS_MW, $ts);
// $options += [ 'timecorrection' => true, 'format' => true ];
// if ($options['timecorrection'] !== false) {
// if ($options['timecorrection'] === true) {
// if ($options['timecorrection'] != false) {
// if ($options['timecorrection'] == true) {
// $offset = $user->getOption('timecorrection');
// } else {
// $offset = $options['timecorrection'];
// }
// $ts = this.userAdjust($ts, $offset);
// }
// if ($options['format'] === true) {
// if ($options['format'] == true) {
// $format = $user->getDatePreference();
// } else {
// $format = $options['format'];
@ -2510,10 +2514,10 @@ public class XomwLanguage {
// public function getHumanTimestamp(
// MWTimestamp $time, MWTimestamp $relativeTo = null, User $user = null
// ) {
// if ($relativeTo === null) {
// if ($relativeTo == null) {
// $relativeTo = new MWTimestamp();
// }
// if ($user === null) {
// if ($user == null) {
// $user = RequestContext::getMain()->getUser();
// }
//
@ -2552,7 +2556,7 @@ public class XomwLanguage {
// (int)$relativeTo->timestamp->format('w'));
// $days = $diff->days ?: (int)$diffDay;
// if ($diff->invert || $days > 5
// && $ts->timestamp->format('Y') !== $relativeTo->timestamp->format('Y')
// && $ts->timestamp->format('Y') != $relativeTo->timestamp->format('Y')
// ) {
// // Timestamps are in different years: use full timestamp
// // Also do full timestamp for future dates
@ -2752,7 +2756,7 @@ public class XomwLanguage {
// * @return boolean
// */
// function isMultibyte($str) {
// return strlen($str) !== mb_strlen($str);
// return strlen($str) != mb_strlen($str);
// }
//
// /**
@ -2896,7 +2900,7 @@ public class XomwLanguage {
// static $full = null;
// static $half = null;
//
// if ($full === null) {
// if ($full == null) {
// $fullWidth = "";
// $halfWidth = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
// $full = str_split($fullWidth, 3);
@ -3050,7 +3054,7 @@ public class XomwLanguage {
// function transformUsingPairFile($file, $String) {
// if (!isset(this.transformData[$file])) {
// $data = wfGetPrecompiledData($file);
// if ($data === false) {
// if ($data == false) {
// throw new MWException(__METHOD__ . ": The transformation file $file is missing");
// }
// this.transformData[$file] = new ReplacementArray($data);
@ -3340,69 +3344,168 @@ public class XomwLanguage {
// $number = strtr($number, [ ',' => '' ]);
// return $number;
// }
//
// /**
// * Adds commas to a given number
// * @since 1.19
// * @param mixed $number
// * @return String
// */
// function commafy($number) {
// $digitGroupingPattern = this.digitGroupingPattern();
// if ($number === null) {
// return '';
// }
//
// if (!$digitGroupingPattern || $digitGroupingPattern === "###,###,###") {
// // default grouping is at thousands, use the same for ###,###,### pattern too.
// return strrev((String)preg_replace('/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev($number)));
// } else {
// // Ref: http://cldr.unicode.org/translation/number-patterns
// $sign = "";
// if (intval($number) < 0) {
// // For negative numbers apply the algorithm like positive number and add sign.
// $sign = "-";
// $number = substr($number, 1);
// }
// $integerPart = [];
// $decimalPart = [];
// $numMatches = preg_match_all("/(#+)/", $digitGroupingPattern, $matches);
// preg_match("/\d+/", $number, $integerPart);
// preg_match("/\.\d*/", $number, $decimalPart);
// $groupedNumber = (count($decimalPart) > 0) ? $decimalPart[0] : "";
// if ($groupedNumber === $number) {
// // the String does not have any number part. Eg: .12345
// return $sign . $groupedNumber;
// }
// $start = $end = ($integerPart) ? strlen($integerPart[0]) : 0;
// while ($start > 0) {
// $match = $matches[0][$numMatches - 1];
// $matchLen = strlen($match);
// $start = $end - $matchLen;
// if ($start < 0) {
// $start = 0;
// }
// $groupedNumber = substr($number, $start, $end -$start) . $groupedNumber;
// $end = $start;
// if ($numMatches > 1) {
// // use the last pattern for the rest of the number
// $numMatches--;
// }
// if ($start > 0) {
// $groupedNumber = "," . $groupedNumber;
// }
// }
// return $sign . $groupedNumber;
// }
// }
//
// /**
// * @return String
// */
// function digitGroupingPattern() {
// return self::$dataCache->getItem(this.mCode, 'digitGroupingPattern');
// }
//
/**
* Adds commas to a given number
* @since 1.19
* @param mixed $number
* @return String
*/
private static byte[] DIGIT_GROUPING_PATTERN_MILLION = Bry_.new_a7("###,###,###");
public byte[] commafy(byte[] number) {
// ignore nulls
if (number == null) {
return Bry_.Empty;
}
// get number vars
int numberLen = number.length;
int integerBgn = 0;
// check for negative; note that MW casts String to number and checks if less than 0
boolean negative = false;
if (numberLen > 0 && number[0] == Byte_ascii.Dash) {
negative = true;
integerBgn = 1;
}
// get integer, decimal pos
int integerEnd = -1, decimalBgn = -1;
boolean decimalExists = false;
for (int i = integerBgn; i < numberLen; i++) {
switch (number[i]) {
// update integerEnd / decimalEnd
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
if (decimalExists) {
}
else {
integerEnd = i + 1;
}
break;
// switch to decimalMode
case Byte_ascii.Dot:
decimalExists = true;
decimalBgn = i;
i = numberLen; // break loop
break;
}
}
int integerLen = integerEnd - integerBgn;
if (digitGroupingPattern == null || Bry_.Eq(digitGroupingPattern, DIGIT_GROUPING_PATTERN_MILLION)) {
// default grouping is at thousands, use the same for ###,###,### pattern too.
// return strrev((String)preg_replace('/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev(number)));
if (negative)
tmp_commafy.Add_byte(Byte_ascii.Dash);
// calculate seg before 1st comma
int seg_0 = (integerLen) % 3;
if (seg_0 == 0 // handle 3x digit; EX: "123", "123456"
&& integerLen > 0) // ignore numbers with no integer portion; EX: ".123"
seg_0 = 3; // set seg_0 to 3
// print digits before 1st comma; EX: 12345 -> "12"
if (seg_0 > 0) {
tmp_commafy.Add_mid(number, integerBgn, integerBgn + seg_0);
integerBgn = integerBgn + seg_0;
}
// print digits in groups of 3; add comma to start
for (int i = integerBgn; i < integerEnd; i += 3) {
tmp_commafy.Add_byte_comma();
tmp_commafy.Add_mid(number, i, i + 3);
}
// print decimal portion if it exists
if (decimalExists)
tmp_commafy.Add_mid(number, decimalBgn, number.length);
return tmp_commafy.To_bry_and_clear();
}
else {
// Ref: http://cldr.unicode.org/translation/number-patterns
// EX: MessagesHi.php; "##,##,###";
// NOTE: this entire block follows MW approach and prints number from right-to-left
// XOMW.REGEX: rewritten b/c of multiple preg_match
// preg_match("/\d+/", number, integerPart);
// preg_match("/\.\d*/", number, decimalPart);
// decimal exists; add it first
if (decimalBgn != -1)
tmp_commafy.Add_reverse_mid(number, decimalBgn, numberLen);
// no integer portion; exit
if (integerBgn == -1) {
// the String does not have any number part. Eg: .12345
return number;
}
// init vars for digitGroupingPattern
int numMatches = 0;
int digitGroupingPatternLen = digitGroupingPattern.length;
tmp_matches.Clear();
// parse digitGroupingPattern for groups of "#"; EX: "##,###" -> 0,2; 3,6
Int_2_ref match = null;
boolean matchContinued = false;
for (int i = 0; i < digitGroupingPatternLen; i++) {
if (digitGroupingPattern[i] == Byte_ascii.Hash) {
if (matchContinued) {
match.Val_1_(i + 1);
}
else {
match = new Int_2_ref(i, i + 1);
tmp_matches.Add(match);
numMatches++;
matchContinued = true;
}
}
else {
matchContinued = false;
}
}
// set start and end; note that they default to integerEnd
int start = -1, end = -1;
start = end = integerEnd != -1 ? integerEnd : 0;
while (start > integerBgn) {
// get rightmost grouping of "#" from digitGroupingPattern
Int_2_ref curMatch = (Int_2_ref)tmp_matches.Get_at(numMatches - 1);
int matchLen = curMatch.Val_1() - curMatch.Val_0();
// calc start / end positions based on matchLen
start = end - matchLen;
if (start < integerBgn) {
start = integerBgn;
}
// add number
tmp_commafy.Add_reverse_mid(number, start, end);
end = start;
if (numMatches > 1) {
// use the last pattern for the rest of the number
numMatches--;
}
// add comma if more digits still available
if (start > integerBgn) {
tmp_commafy.Add_byte(Byte_ascii.Comma);
}
}
// add negative if exists
if (negative)
tmp_commafy.Add_byte(Byte_ascii.Dash);
return tmp_commafy.To_reversed_bry_and_clear();
}
}
public void setDigitGroupingPattern(byte[] v) {
this.digitGroupingPattern = v;
}
// /**
// * @return array
// */
@ -3724,7 +3827,7 @@ public class XomwLanguage {
// * @return int
// */
// private function truncate_skip(&$ret, $text, $search, $start, $len = null) {
// if ($len === null) {
// if ($len == null) {
// $len = -1; // -1 means "no limit" for strcspn
// } elseif ($len < 0) {
// $len = 0; // sanity
@ -3789,7 +3892,7 @@ public class XomwLanguage {
// foreach (array_values($forms) as $rule) {
// $form = $rule[0];
//
// if ($form === '@metadata') {
// if ($form == '@metadata') {
// continue;
// }
//
@ -3798,12 +3901,12 @@ public class XomwLanguage {
// $regex = '/' . addcslashes($form, '/') . '/u';
// $patternMatches = preg_match($regex, $word);
//
// if ($patternMatches === false) {
// if ($patternMatches == false) {
// wfLogWarning(
// 'An error occurred while processing grammar. ' .
// "Word: '$word'. Regex: /$form/."
// );
// } elseif ($patternMatches === 1) {
// } elseif ($patternMatches == 1) {
// $word = preg_replace($regex, $replacement, $word);
//
// break;
@ -3842,7 +3945,7 @@ public class XomwLanguage {
// public function getGrammarTransformations() {
// $languageCode = this.getCode();
//
// if (self::$grammarTransformations === null) {
// if (self::$grammarTransformations == null) {
// self::$grammarTransformations = new MapCacheLRU(10);
// }
//
@ -3859,7 +3962,7 @@ public class XomwLanguage {
// true
// );
//
// if ($data === null) {
// if ($data == null) {
// throw new MWException("Invalid grammar data for \"$languageCode\".");
// }
//
@ -3893,10 +3996,10 @@ public class XomwLanguage {
// return '';
// }
// $forms = this.preConvertPlural($forms, 2);
// if ($gender === 'male') {
// if ($gender == 'male') {
// return $forms[0];
// }
// if ($gender === 'female') {
// if ($gender == 'female') {
// return $forms[1];
// }
// return isset($forms[2]) ? $forms[2] : $forms[0];
@ -3951,7 +4054,7 @@ public class XomwLanguage {
// foreach ($forms as $index => $form) {
// if (preg_match('/\d+=/i', $form)) {
// $pos = strpos($form, '=');
// if (substr($form, 0, $pos) === (String)$count) {
// if (substr($form, 0, $pos) == (String)$count) {
// return substr($form, $pos + 1);
// }
// unset($forms[$index]);
@ -3993,11 +4096,11 @@ public class XomwLanguage {
// */
// public function embedBidi($text = '') {
// $dir = Language::strongDirFromContent($text);
// if ($dir === 'ltr') {
// if ($dir == 'ltr') {
// // Wrap in LEFT-TO-RIGHT EMBEDDING ... POP DIRECTIONAL FORMATTING
// return self::$lre . $text . self::$pdf;
// }
// if ($dir === 'rtl') {
// if ($dir == 'rtl') {
// // Wrap in RIGHT-TO-LEFT EMBEDDING ... POP DIRECTIONAL FORMATTING
// return self::$rle . $text . self::$pdf;
// }
@ -4036,13 +4139,13 @@ public class XomwLanguage {
//
// // If all else fails, return a standard duration or timestamp description.
// $time = strtotime($str, $now);
// if ($time === false) { // Unknown format. Return it as-is in case.
// if ($time == false) { // Unknown format. Return it as-is in case.
// return $str;
// } elseif ($time !== strtotime($str, $now + 1)) { // It's a relative timestamp.
// } elseif ($time != strtotime($str, $now + 1)) { // It's a relative timestamp.
// // The result differs based on current time, so it's a duration length.
// return this.formatDuration($time);
// } else { // It's an absolute timestamp.
// if ($time === 0) {
// if ($time == 0) {
// // wfTimestamp() handles 0 as current time instead of epoch.
// $time = '19700101000000';
// }
@ -4290,7 +4393,7 @@ public class XomwLanguage {
// * @since 1.22
// */
// public function getParentLanguage() {
// if (this.mParentLanguage !== false) {
// if (this.mParentLanguage != false) {
// return this.mParentLanguage;
// }
//
@ -4317,7 +4420,7 @@ public class XomwLanguage {
// * @return boolean
// */
// public function equals(Language $lang) {
// return $lang->getCode() === this.mCode;
// return $lang->getCode() == this.mCode;
// }
//
// /**
@ -4454,7 +4557,7 @@ public class XomwLanguage {
// * @return array Non-empty array, ending in "en"
// */
// public static function getFallbacksFor($code) {
// if ($code === 'en' || !Language::isValidBuiltInCode($code)) {
// if ($code == 'en' || !Language::isValidBuiltInCode($code)) {
// return [];
// }
// // For unknown languages, fallbackSequence returns an empty array,
@ -4534,7 +4637,7 @@ public class XomwLanguage {
// * @return mixed
// */
// function fixVariableInNamespace($talk) {
// if (strpos($talk, '$1') === false) {
// if (strpos($talk, '$1') == false) {
// return $talk;
// }
//
@ -4570,16 +4673,16 @@ public class XomwLanguage {
// */
// public function formatExpiry($expiry, $format = true, $infinity = 'infinity') {
// static $dbInfinity;
// if ($dbInfinity === null) {
// if ($dbInfinity == null) {
// $dbInfinity = wfGetDB(DB_SLAVE)->getInfinity();
// }
//
// if ($expiry == '' || $expiry === 'infinity' || $expiry == $dbInfinity) {
// return $format === true
// if ($expiry == '' || $expiry == 'infinity' || $expiry == $dbInfinity) {
// return $format == true
// ? this.getMessageFromDB('infiniteblock')
// : $infinity;
// } else {
// return $format === true
// return $format == true
// ? this.timeanddate($expiry, /* User preference timezone */ true)
// : wfTimestamp($format, $expiry);
// }
@ -4590,8 +4693,8 @@ public class XomwLanguage {
// *
// * @param int|float $seconds
// * @param array $format An optional argument that formats the returned String in different ways:
// * If $format['avoid'] === 'avoidseconds': don't show seconds if $seconds >= 1 hour,
// * If $format['avoid'] === 'avoidminutes': don't show seconds/minutes if $seconds > 48 hours,
// * If $format['avoid'] == 'avoidseconds': don't show seconds if $seconds >= 1 hour,
// * If $format['avoid'] == 'avoidminutes': don't show seconds/minutes if $seconds > 48 hours,
// * If $format['noabbrevs'] is true: use 'seconds' and friends instead of 'seconds-abbrev'
// * and friends.
// * @note For backwards compatibility, $format may also be one of the strings 'avoidseconds'
@ -4653,7 +4756,7 @@ public class XomwLanguage {
// }
// } else {
// $days = floor($seconds / 86400);
// if ($format['avoid'] === 'avoidminutes') {
// if ($format['avoid'] == 'avoidminutes') {
// $hours = round(($seconds - $days * 86400) / 3600);
// if ($hours == 24) {
// $hours = 0;
@ -4662,7 +4765,7 @@ public class XomwLanguage {
// $s = $daysMsg->params(this.formatNum($days))->text();
// $s .= ' ';
// $s .= $hoursMsg->params(this.formatNum($hours))->text();
// } elseif ($format['avoid'] === 'avoidseconds') {
// } elseif ($format['avoid'] == 'avoidseconds') {
// $hours = floor(($seconds - $days * 86400) / 3600);
// $minutes = round(($seconds - $days * 86400 - $hours * 3600) / 60);
// if ($minutes == 60) {

View File

@ -0,0 +1,129 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.languages; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*;
import org.junit.*; import gplx.core.tests.*;
import gplx.xowa.langs.*;
public class XomwLanguageTest {
private final XomwLanguageFxt fxt = new XomwLanguageFxt();
@Test public void Commafy_standard() {
// basic
fxt.Test_commafy("1" , "1");
fxt.Test_commafy("12" , "12");
fxt.Test_commafy("123" , "123");
fxt.Test_commafy("1234" , "1,234");
fxt.Test_commafy("12345" , "12,345");
fxt.Test_commafy("123456" , "123,456");
fxt.Test_commafy("1234567" , "1,234,567");
fxt.Test_commafy("12345678" , "12,345,678");
fxt.Test_commafy("123456789" , "123,456,789");
fxt.Test_commafy("1234567890" , "1,234,567,890");
// decimal
fxt.Test_commafy("1.234" , "1.234");
fxt.Test_commafy("1234.456" , "1,234.456");
fxt.Test_commafy(".456" , ".456");
// negative
fxt.Test_commafy("-1" , "-1");
fxt.Test_commafy("-12" , "-12");
fxt.Test_commafy("-123" , "-123");
fxt.Test_commafy("-1234" , "-1,234");
fxt.Test_commafy("-12345" , "-12,345");
fxt.Test_commafy("-123456" , "-123,456");
fxt.Test_commafy("-1234567" , "-1,234,567");
fxt.Test_commafy("-12345678" , "-12,345,678");
fxt.Test_commafy("-123456789" , "-123,456,789");
fxt.Test_commafy("-1234567890" , "-1,234,567,890");
}
@Test public void Commafy_custom_standard() {
fxt.Init_digitGroupingPattern("###,###");
// basic
fxt.Test_commafy("1" , "1");
fxt.Test_commafy("12" , "12");
fxt.Test_commafy("123" , "123");
fxt.Test_commafy("1234" , "1,234");
fxt.Test_commafy("12345" , "12,345");
fxt.Test_commafy("123456" , "123,456");
fxt.Test_commafy("1234567" , "1,234,567");
fxt.Test_commafy("12345678" , "12,345,678");
fxt.Test_commafy("123456789" , "123,456,789");
fxt.Test_commafy("1234567890" , "1,234,567,890");
// decimal
fxt.Test_commafy("1.234" , "1.234");
fxt.Test_commafy("1234.456" , "1,234.456");
fxt.Test_commafy(".456" , ".456");
// negative
fxt.Test_commafy("-1" , "-1");
fxt.Test_commafy("-12" , "-12");
fxt.Test_commafy("-123" , "-123");
fxt.Test_commafy("-1234" , "-1,234");
fxt.Test_commafy("-12345" , "-12,345");
fxt.Test_commafy("-123456" , "-123,456");
fxt.Test_commafy("-1234567" , "-1,234,567");
fxt.Test_commafy("-12345678" , "-12,345,678");
fxt.Test_commafy("-123456789" , "-123,456,789");
fxt.Test_commafy("-1234567890" , "-1,234,567,890");
}
@Test public void Commafy_custom_hindi() {
fxt.Init_digitGroupingPattern("##,##,###");
// basic
fxt.Test_commafy("1" , "1");
fxt.Test_commafy("12" , "12");
fxt.Test_commafy("123" , "123");
fxt.Test_commafy("1234" , "1,234");
fxt.Test_commafy("12345" , "12,345");
fxt.Test_commafy("123456" , "1,23,456");
fxt.Test_commafy("1234567" , "12,34,567");
fxt.Test_commafy("12345678" , "1,23,45,678");
fxt.Test_commafy("123456789" , "12,34,56,789");
fxt.Test_commafy("1234567890" , "1,23,45,67,890");
// decimal
fxt.Test_commafy("1.234" , "1.234");
fxt.Test_commafy("1234.456" , "1,234.456");
fxt.Test_commafy(".456" , ".456");
// negative
fxt.Test_commafy("-1" , "-1");
fxt.Test_commafy("-12" , "-12");
fxt.Test_commafy("-123" , "-123");
fxt.Test_commafy("-1234" , "-1,234");
fxt.Test_commafy("-12345" , "-12,345");
fxt.Test_commafy("-123456" , "-1,23,456");
fxt.Test_commafy("-1234567" , "-12,34,567");
fxt.Test_commafy("-12345678" , "-1,23,45,678");
fxt.Test_commafy("-123456789" , "-12,34,56,789");
fxt.Test_commafy("-1234567890" , "-1,23,45,67,890");
}
}
class XomwLanguageFxt {
private final XomwLanguage lang;
public XomwLanguageFxt() {
Xoae_app app = Xoa_app_fxt.Make__app__edit();
Xol_lang_itm xoLang = new Xol_lang_itm(app.Lang_mgr(), Bry_.new_a7("en"));
this.lang = new XomwLanguage(xoLang);
}
public void Init_digitGroupingPattern(String digitGroupingPattern) {
lang.setDigitGroupingPattern(Bry_.new_u8(digitGroupingPattern));
}
public void Test_commafy(String raw, String expd) {
Gftest.Eq__str(expd, lang.commafy(Bry_.new_u8(raw)));
}
}