mirror of https://github.com/gnosygnu/xowa
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
558 lines
22 KiB
558 lines
22 KiB
/*
|
|
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;
|
|
import java.lang.*;
|
|
import gplx.core.strings.*; import gplx.langs.gfs.*; import gplx.core.envs.*;
|
|
public class String_ {
|
|
// -------- BASELIB_COPY --------
|
|
public static final Class<?> Cls_ref_type = String.class;
|
|
public static final String Cls_val_name = "str" + "ing";
|
|
public static final int Find_none = -1, Pos_neg1 = -1;
|
|
public static final String Empty = "", Null_mark = "<<NULL>>", Tab = "\t", Lf = "\n", CrLf = "\r\n", Nl = "\n";
|
|
|
|
public static boolean Eq(String lhs, String rhs) {return lhs == null ? rhs == null : lhs.equals(rhs);}
|
|
public static int Len(String s) {return s.length();}
|
|
public static char CharAt(String s, int i) {return s.charAt(i);}
|
|
|
|
public static String new_u8(byte[] v) {return v == null ? null : new_u8(v, 0, v.length);}
|
|
public static String new_u8(byte[] v, int bgn, int end) {
|
|
try {
|
|
return v == null
|
|
? null
|
|
: new String(v, bgn, end - bgn, "UTF-8");
|
|
}
|
|
catch (Exception e) {Err_.Noop(e); throw Err_.new_("core", "unsupported encoding", "bgn", bgn, "end", end);}
|
|
}
|
|
|
|
// use C# flavor ("a {0}") rather than Java format ("a %s"); also: (a) don't fail on format errors; (b) escape brackets by doubling
|
|
private static final char FORMAT_ITM_LHS = '{', FORMAT_ITM_RHS = '}';
|
|
public static String Format(String fmt, Object... args) {
|
|
// method vars
|
|
int args_len = Array_.Len_obj(args);
|
|
if (args_len == 0) return fmt; // nothing to format
|
|
int fmt_len = Len(fmt);
|
|
|
|
// loop vars
|
|
int pos = 0; String arg_idx_str = ""; boolean inside_brackets = false;
|
|
String_bldr bfr = String_bldr_.new_();
|
|
while (pos < fmt_len) { // loop over every char; NOTE: UT8-SAFE b/c only checking for "{"; "}"
|
|
char c = CharAt(fmt, pos);
|
|
if (inside_brackets) {
|
|
if (c == FORMAT_ITM_LHS) { // first FORMAT_ITM_LHS is fake; add FORMAT_ITM_LHS and whatever is in arg_idx_str
|
|
bfr.Add(FORMAT_ITM_LHS).Add(arg_idx_str);
|
|
arg_idx_str = "";
|
|
}
|
|
else if (c == FORMAT_ITM_RHS) { // itm completed
|
|
int args_idx = Int_.Parse_or(arg_idx_str, Int_.Min_value);
|
|
String itm = args_idx != Int_.Min_value && Int_.Between(args_idx, 0, args_len - 1) // check (a) args_idx is num; (b) args_idx is in bounds
|
|
? Object_.Xto_str_strict_or_empty(args[args_idx]) // valid; add itm
|
|
: String_.Concat_any(FORMAT_ITM_LHS, arg_idx_str, FORMAT_ITM_RHS); // not valid; just add String
|
|
bfr.Add(itm);
|
|
inside_brackets = false;
|
|
arg_idx_str = "";
|
|
}
|
|
else
|
|
arg_idx_str += c;
|
|
}
|
|
else {
|
|
if (c == FORMAT_ITM_LHS || c == FORMAT_ITM_RHS) {
|
|
boolean pos_is_end = pos == fmt_len - 1;
|
|
if (pos_is_end) // last char is "{" or "}" (and not inside_brackets); ignore and just ad
|
|
bfr.Add(c);
|
|
else {
|
|
char next = CharAt(fmt, pos + 1);
|
|
if (next == c) { // "{{" or "}}": escape by doubling
|
|
bfr.Add(c);
|
|
pos++;
|
|
}
|
|
else
|
|
inside_brackets = true;
|
|
}
|
|
}
|
|
else
|
|
bfr.Add(c);
|
|
}
|
|
pos++;
|
|
}
|
|
if (Len(arg_idx_str) > 0) // unclosed bracket; add FORMAT_ITM_LHS and whatever is in arg_idx_str; ex: "{0"
|
|
bfr.Add(FORMAT_ITM_LHS).Add(arg_idx_str);
|
|
return bfr.To_str();
|
|
}
|
|
|
|
// -------- TO_MIGRATE --------
|
|
public static String cast(Object v) {return (String)v;}
|
|
public static String as_(Object obj) {return obj instanceof String ? (String)obj : null;}
|
|
public static String new_a7(byte[] v) {return v == null ? null : new_a7(v, 0, v.length);}
|
|
public static String new_a7(byte[] v, int bgn, int end) {
|
|
try {
|
|
return v == null
|
|
? null
|
|
: new String(v, bgn, end - bgn, "ASCII");
|
|
}
|
|
catch (Exception e) {throw Err_.new_exc(e, "core", "unsupported encoding");}
|
|
}
|
|
public static String new_u8__by_len(byte[] v, int bgn, int len) {
|
|
int v_len = v.length;
|
|
if (bgn + len > v_len) len = v_len - bgn;
|
|
return new_u8(v, bgn, bgn + len);
|
|
}
|
|
public static String[] Ary_add(String[]... arys) {
|
|
if (arys == null) return String_.Ary_empty;
|
|
int arys_len = arys.length;
|
|
int rv_len = 0;
|
|
for (int i = 0; i < arys_len; i++) {
|
|
String[] ary = arys[i];
|
|
rv_len += ary.length;
|
|
}
|
|
int rv_idx = 0;
|
|
String[] rv = new String[rv_len];
|
|
for (int i = 0; i < arys_len; i++) {
|
|
String[] ary = arys[i];
|
|
int ary_len = ary.length;
|
|
for (int j = 0; j < ary_len; j++)
|
|
rv[rv_idx++] = ary[j];
|
|
}
|
|
return rv;
|
|
}
|
|
public static boolean Len_gt_0(String s) {return s != null && s.length() > 0;}
|
|
public static boolean Len_eq_0(String s) {return s == null || s.length() == 0;}
|
|
public static String Lower(String s) {return s.toLowerCase();}
|
|
public static String Upper(String s) {return s.toUpperCase();}
|
|
public static String CaseNormalize(boolean caseSensitive, String s) {return caseSensitive ? s : String_.Lower(s);}
|
|
public static String Trim(String s) {return s.trim();}
|
|
public static String Mid(String s, int bgn) {return s.substring(bgn);}
|
|
public static String Replace(String s, String find, String replace) {return s.replace(find, replace);}
|
|
public static char[] XtoCharAry(String s) {return s.toCharArray();}
|
|
public static int CodePointAt(String s, int i) {return s.codePointAt(i);}
|
|
public static boolean Has(String s, String find) {return s.indexOf(find) != String_.Find_none;}
|
|
public static boolean Has_at_bgn(String s, String v) {return s.startsWith(v);}
|
|
public static boolean Has_at_end(String s, String v) {return s.endsWith(v);}
|
|
public static int FindFwd(String s, String find) {return s.indexOf(find);}
|
|
public static int FindFwd(String s, String find, int pos) {return s.indexOf(find, pos);}
|
|
public static int FindFwd(String s, String find, int bgn, int end) {
|
|
int rv = FindFwd(s, find, bgn);
|
|
return rv > end ? String_.Find_none : rv;
|
|
}
|
|
public static int FindBwd(String s, String find) {return s.lastIndexOf(find);}
|
|
public static int FindBwd(String s, String find, int pos) {
|
|
return s.lastIndexOf(find, pos);
|
|
}
|
|
public static int FindBetween(String s, String find, int bgn, int end) {
|
|
int rv = FindFwd(s, find, bgn);
|
|
return (rv > end) ? String_.Find_none : rv;
|
|
}
|
|
public static int FindAfter(String s, String find, int bgn) {
|
|
int rv = FindFwd(s, find, bgn);
|
|
return rv == String_.Find_none ? String_.Find_none : rv + Len(find);
|
|
}
|
|
public static int FindAfterRev(String s, String find, int pos) {
|
|
int rv = FindBwd(s, find, pos);
|
|
return rv == String_.Find_none ? String_.Find_none : rv + Len(find);
|
|
}
|
|
public static int Count(String s, String part) {
|
|
int count = 0, pos = -1; // -1 b/c first pass must be 0 (see pos + 1 below)
|
|
do {
|
|
pos = FindFwd(s, part, pos + 1);
|
|
if (pos == String_.Find_none) break;
|
|
count++;
|
|
} while (true);
|
|
return count;
|
|
}
|
|
public static boolean EqAny(String lhs, String... rhsAry) {
|
|
for (int i = 0; i < rhsAry.length; i++)
|
|
if (Eq(lhs, rhsAry[i])) return true;
|
|
return false;
|
|
}
|
|
public static boolean EqNot(String lhs, String rhs) {return !Object_.Eq(lhs, rhs);}
|
|
public static boolean EqEmpty(String lhs) {return lhs.equals("");}
|
|
public static String IfNullOrEmpty(String s, String or) {return s == null || s.length() == 0 ? or : s;}
|
|
public static int Compare_as_ordinals(String lhs, String rhs) {return lhs.compareTo(rhs);}
|
|
public static int Compare_ignoreCase(String lhs, String rhs) {
|
|
if (lhs == null && rhs != null) return CompareAble_.Less;
|
|
else if (lhs != null && rhs == null) return CompareAble_.More;
|
|
else if (lhs == null && rhs == null) return CompareAble_.Same;
|
|
else return lhs.compareToIgnoreCase(rhs);
|
|
//#-
|
|
/*
|
|
if (lhs == null && rhs != null) return CompareAble_.Less;
|
|
else if (lhs != null && rhs == null) return CompareAble_.More;
|
|
else if (lhs == null && rhs == null) return CompareAble_.Same;
|
|
else return lhs.compareToIgnoreCase(rhs);
|
|
*/
|
|
}
|
|
public static int Compare(String lhs, String rhs) {
|
|
int compare = lhs.compareTo(rhs);
|
|
if (compare == CompareAble_.Same) return CompareAble_.Same;
|
|
else if (compare < CompareAble_.Same) return CompareAble_.Less;
|
|
else /* (compare > CompareAble_.Same) */ return CompareAble_.More;
|
|
}
|
|
public static int Compare_byteAry(String lhs, String rhs) {
|
|
int lhsLen = lhs.length(), rhsLen = rhs.length();
|
|
int aryLen = lhsLen < rhsLen ? lhsLen : rhsLen;
|
|
int[] lhsAry = XtoIntAry(lhs, aryLen), rhsAry = XtoIntAry(rhs, aryLen);
|
|
for (int i = 0; i < aryLen; i++) {
|
|
int comp = Int_.Compare(lhsAry[i], rhsAry[i]);
|
|
if (comp != CompareAble_.Same) return comp;
|
|
}
|
|
return Int_.Compare(lhsLen, rhsLen);
|
|
}
|
|
public static int[] XtoIntAry(String s, int len) {
|
|
int[] rv = new int[len];
|
|
for (int i = 0; i < len; i++)
|
|
rv[i] = (int)s.charAt(i);
|
|
return rv;
|
|
}
|
|
public static String Coalesce(String s, String alt) {return Len_eq_0(s) ? alt : s;}
|
|
public static boolean In(String s, String... ary) {
|
|
for (String itm : ary)
|
|
if (String_.Eq(s, itm)) return true;
|
|
return false;
|
|
}
|
|
|
|
public static String new_charAry_(char[] ary, int bgn, int len) {return new String(ary, bgn, len);}
|
|
public static String Mid(String s, int bgn, int end) {
|
|
try {return Mid_lang(s, bgn, end - bgn);}
|
|
catch (Exception e) {
|
|
int len = s == null ? 0 : Len(s);
|
|
String msg = "";
|
|
if (s == null) msg = "s is null";
|
|
else if (bgn > end) msg = "@bgn > @end";
|
|
else if (bgn < 0 || bgn >= len) msg = "@bgn is invalid";
|
|
else if (end < 0 || end > len) msg = "@end is invalid";
|
|
throw Err_.new_exc(e, "core", msg, "s", s, "bgn", bgn, "end", end, "len", len);
|
|
}
|
|
}
|
|
public static String MidByLenSafe(String s, int bgn, int len) {
|
|
if (bgn + len >= Len(s)) len = Len(s) - bgn;
|
|
return Mid_lang(s, bgn, len);
|
|
}
|
|
public static String MidByLen(String s, int bgn, int len) {return Mid_lang(s, bgn, len);}
|
|
public static String GetStrBefore(String s, String spr) {
|
|
int sprPos = String_.FindFwd(s, spr); if (sprPos == String_.Find_none) throw Err_.new_wo_type("could not find spr", "s", s, "spr", spr);
|
|
return Mid(s, 0, sprPos);
|
|
}
|
|
public static String GetStrAfter(String s, String spr) {
|
|
int sprPos = String_.FindFwd(s, spr); if (sprPos == String_.Find_none) throw Err_.new_wo_type("could not find spr", "s", s, "spr", spr);
|
|
return Mid(s, sprPos + 1);
|
|
}
|
|
public static String LimitToFirst(String s, int len) {
|
|
if (len < 0) throw Err_.new_invalid_arg("< 0", "len", len);
|
|
int sLen = Len(s); if (len > sLen) return s;
|
|
return Mid_lang(s, 0, len);
|
|
}
|
|
public static String LimitToLast(String s, int len) {
|
|
if (len < 0) throw Err_.new_invalid_arg("< 0", "len", len);
|
|
int sLen = Len(s); if (len > sLen) return s;
|
|
return Mid_lang(s, sLen - len, len);
|
|
}
|
|
public static String DelBgn(String s, int count) {
|
|
if (count < 0) throw Err_.new_invalid_arg("< 0", "count", count);
|
|
if (s == null) throw Err_.new_null();
|
|
int len = Len(s); if (count > len) throw Err_.new_invalid_arg("> @len", "count", count, "len", len);
|
|
return String_.Mid(s, count);
|
|
}
|
|
public static String DelBgnIf(String s, String find) {
|
|
if (s == null) throw Err_.new_null();
|
|
if (find == null) throw Err_.new_null();
|
|
return Has_at_bgn(s, find) ? String_.Mid(s, Len(find)) : s;
|
|
}
|
|
public static String DelEnd(String s, int count) {
|
|
if (count < 0) throw Err_.new_invalid_arg("< 0", "count", count);
|
|
if (s == null) throw Err_.new_null();
|
|
int len = Len(s); if (count > len) throw Err_.new_invalid_arg("> len", "count", count, "len", len);
|
|
return Mid_lang(s, 0, len + -count);
|
|
}
|
|
public static String DelEndIf(String s, String find) {
|
|
if (s == null) throw Err_.new_null();
|
|
if (find == null) throw Err_.new_null();
|
|
return Has_at_end(s, find) ? Mid_lang(s, 0, Len(s) - Len(find)) : s;
|
|
}
|
|
public static String LowerFirst(String s) {
|
|
int len = Len(s); if (len == 0) return String_.Empty;
|
|
String char0 = Lower(Mid_lang(s, 0, 1));
|
|
return len == 1 ? char0 : char0 + Mid(s, 1);
|
|
}
|
|
public static String UpperFirst(String s) {
|
|
int len = Len(s); if (len == 0) return String_.Empty;
|
|
String char0 = Upper(Mid_lang(s, 0, 1));
|
|
return len == 1 ? char0 : char0 + Mid(s, 1);
|
|
}
|
|
public static String PadBgn(String s, int totalLen, String pad) {return Pad(s, totalLen, pad, true);}
|
|
public static String PadEnd(String s, int totalLen, String pad) {return Pad(s, totalLen, pad, false);}
|
|
@gplx.Internal protected static String Pad(String s, int totalLen, String pad, boolean bgn) {
|
|
int sLen = Len(s);
|
|
int padLen = totalLen - sLen; if (padLen < 0) return s;
|
|
String_bldr sb = String_bldr_.new_();
|
|
if (!bgn) sb.Add(s);
|
|
for (int i = 0; i < padLen; i++)
|
|
sb.Add(pad);
|
|
if (bgn) sb.Add(s);
|
|
return sb.To_str();
|
|
}
|
|
public static String TrimEnd(String s) {if (s == null) return null;
|
|
int len = String_.Len(s);
|
|
if (len == 0) return s;
|
|
int last = len;
|
|
for (int i = len; i > 0; i--) {
|
|
char c = s.charAt(i - 1);
|
|
last = i;
|
|
if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
|
|
break;
|
|
}
|
|
}
|
|
return (last == len) ? s : Mid_lang(s, 0, last);
|
|
}
|
|
public static String Repeat(String s, int count) {
|
|
if (count < 0) throw Err_.new_wo_type("count cannot be negative", "count", count, "s", s);
|
|
String_bldr sb = String_bldr_.new_();
|
|
for (int i = 0; i < count; i++)
|
|
sb.Add(s);
|
|
return sb.To_str();
|
|
}
|
|
public static String Insert(String s, int pos, String toInsert) {
|
|
if (pos < 0 || pos >= String_.Len(s)) throw Err_.new_wo_type("String_.Insert failed; pos invalid", "pos", pos, "s", s, "toInsert", toInsert);
|
|
return s.substring(0, pos) + toInsert + s.substring(pos);
|
|
}
|
|
public static String FormatOrEmptyStrIfNull(String fmt, Object arg) {return arg == null ? "" : Format(fmt, arg);}
|
|
public static String Concat(char... ary) {return new String(ary);}
|
|
public static String Concat(String s1, String s2, String s3) {return s1 + s2 + s3;}
|
|
public static String Concat(String... ary) {
|
|
String_bldr sb = String_bldr_.new_();
|
|
for (String val : ary)
|
|
sb.Add(val);
|
|
return sb.To_str();
|
|
}
|
|
public static String Concat_any(Object... ary) {
|
|
String_bldr sb = String_bldr_.new_();
|
|
for (Object val : ary)
|
|
sb.Add_obj(val);
|
|
return sb.To_str();
|
|
}
|
|
public static String Concat_with_obj(String separator, Object... ary) {
|
|
String_bldr sb = String_bldr_.new_();
|
|
int aryLen = Array_.Len(ary);
|
|
for (int i = 0; i < aryLen; i++) {
|
|
if (i != 0) sb.Add(separator);
|
|
Object val = ary[i];
|
|
sb.Add_obj(Object_.Xto_str_strict_or_empty(val));
|
|
}
|
|
return sb.To_str();
|
|
}
|
|
public static String Concat_with_str(String spr, String... ary) {
|
|
String_bldr sb = String_bldr_.new_();
|
|
int len = ary.length;
|
|
for (int i = 0; i < len; i++) {
|
|
if (i != 0) sb.Add(spr);
|
|
sb.Add_obj(ary[i]);
|
|
}
|
|
return sb.To_str();
|
|
}
|
|
public static String Concat_lines_crlf(String... values) {
|
|
String_bldr sb = String_bldr_.new_();
|
|
for (String val : values)
|
|
sb.Add(val).Add(String_.CrLf);
|
|
return sb.To_str();
|
|
}
|
|
public static String Concat_lines_crlf_skipLast(String... values) {
|
|
String_bldr sb = String_bldr_.new_();
|
|
for (String val : values) {
|
|
if (sb.Count() != 0) sb.Add(String_.CrLf);
|
|
sb.Add(val);
|
|
}
|
|
return sb.To_str();
|
|
}
|
|
public static String Concat_lines_nl(String... values) {
|
|
String_bldr sb = String_bldr_.new_();
|
|
for (String val : values)
|
|
sb.Add(val).Add("\n");
|
|
return sb.To_str();
|
|
}
|
|
public static String Concat_lines_nl_apos_skip_last(String... lines) {
|
|
Bry_bfr bfr = Bry_bfr_.Get();
|
|
try {
|
|
Bry_.New_u8_nl_apos(bfr, lines);
|
|
return bfr.To_str_and_clear();
|
|
}
|
|
finally {bfr.Mkr_rls();}
|
|
}
|
|
public static String Concat_lines_nl_skip_last(String... ary) {
|
|
String_bldr sb = String_bldr_.new_();
|
|
int ary_len = ary.length; int ary_end = ary_len - 1;
|
|
for (int i = 0; i < ary_len; i++) {
|
|
sb.Add(ary[i]);
|
|
if (i != ary_end) sb.Add("\n");
|
|
}
|
|
return sb.To_str();
|
|
}
|
|
|
|
public static String[] Ary(String... ary) {return ary;}
|
|
public static String[] Ary_wo_null(String... ary) {
|
|
List_adp list = List_adp_.New();
|
|
int len = ary.length;
|
|
for (int i = 0; i < len; ++i) {
|
|
String itm = ary[i];
|
|
if (itm == null) continue;
|
|
list.Add(itm);
|
|
}
|
|
return list.To_str_ary();
|
|
}
|
|
public static String AryXtoStr(String... ary) {
|
|
String_bldr sb = String_bldr_.new_();
|
|
for (String s : ary)
|
|
sb.Add(s).Add(";");
|
|
return sb.To_str();
|
|
}
|
|
public static final String[] Ary_empty = new String[0];
|
|
public static String[] Split(String raw, char dlm) {return Split(raw, dlm, false);}
|
|
public static String[] Split(String raw, char dlm, boolean addEmptyIfDlmIsLast) {
|
|
List_adp list = List_adp_.New(); String_bldr sb = String_bldr_.new_();
|
|
int rawLen = String_.Len(raw); char c = '\0';
|
|
for (int i = 0; i < rawLen; i++) {
|
|
c = String_.CharAt(raw, i);
|
|
if (c == dlm) {
|
|
if (!addEmptyIfDlmIsLast && sb.Count() == 0 && i == rawLen - 1) {}
|
|
else list.Add(sb.To_str_and_clear());
|
|
}
|
|
else
|
|
sb.Add(c);
|
|
}
|
|
if (sb.Count() > 0)
|
|
list.Add(sb.To_str_and_clear());
|
|
return list.To_str_ary();
|
|
}
|
|
public static String[] Split(String s, String separator) {return Split_do(s, separator, false);}
|
|
public static String[] SplitLines_crlf(String s) {return Split(s, Op_sys.Wnt.Nl_str());}
|
|
public static String[] SplitLines_nl(String s) {return Split(s, Op_sys.Lnx.Nl_str());}
|
|
public static String[] SplitLines_any(String s) {return Split_do(s, Op_sys.Lnx.Nl_str(), true);}
|
|
public static String[] Split_lang(String s, char c) {return s.split(Character.toString(c));}
|
|
|
|
static String[] Split_do(String s, String spr, boolean skipChar13) {
|
|
if (String_.Eq(s, "") // "".Split('a') return array with one member: ""
|
|
|| String_.Eq(spr, "")) // "a".Split('\0') returns array with one member: "a"
|
|
return new String[] {s};
|
|
List_adp list = List_adp_.New(); String_bldr sb = String_bldr_.new_();
|
|
int i = 0, sprPos = 0; boolean sprMatched = false; char spr0 = CharAt(spr, 0);
|
|
int textLength = Len(s); int sprLength = Len(spr);
|
|
while (true) {
|
|
if (sprMatched
|
|
|| i == textLength) { // last pass; add whatever's in sb to list
|
|
list.Add(sb.To_str_and_clear());
|
|
if (sprMatched && i == textLength) list.Add(""); // if s ends with spr and last pass, add emptyString as last
|
|
sprMatched = false;
|
|
}
|
|
if (i == textLength) break;
|
|
char c = CharAt(s, i);
|
|
if (skipChar13 && c == (char)13) {i++; continue;}
|
|
if (c == spr0) { // matches first char of spr
|
|
sprPos = 1;
|
|
while (true) {
|
|
if (sprPos == sprLength) { // made it to end, must be match
|
|
sprMatched = true;
|
|
break;
|
|
}
|
|
if (i + sprPos == textLength) break; // ran out of s; handles partial match at end of String; ab+, +-
|
|
if (CharAt(s, i + sprPos) != CharAt(spr, sprPos)) break; // no match
|
|
sprPos++;
|
|
}
|
|
if (!sprMatched) // add partial match to sb
|
|
sb.Add(Mid_lang(s, i, sprPos));
|
|
i += sprPos;
|
|
}
|
|
else { // no spr match; just add char, increment pos
|
|
sb.Add(c);
|
|
i++;
|
|
}
|
|
}
|
|
return (String[])list.To_ary(String.class);
|
|
}
|
|
static String Mid_lang(String s, int bgn, int len) {return s.substring(bgn, bgn + len);}
|
|
public static String Extract_after_bwd(String src, String dlm) {
|
|
int dlm_pos = String_.FindBwd(src, dlm); if (dlm_pos == String_.Find_none) return String_.Empty;
|
|
int src_len = String_.Len(src); if (dlm_pos == src_len - 1) return String_.Empty;
|
|
return String_.Mid(src, dlm_pos + 1, src_len);
|
|
}
|
|
public static String Replace_by_pos(String v, int del_bgn, int del_end, String repl) {
|
|
return String_.Mid(v, 0, del_bgn) + repl + String_.Mid(v, del_end, String_.Len(v));
|
|
}
|
|
public static String read_(Object obj) {// NOTE: same as cast; for consistent readability only
|
|
String rv = as_(obj);
|
|
if (rv == null && obj != null) throw Err_.new_type_mismatch(String.class, obj); // NOTE: obj != null needed; EX: cast(null) --> null
|
|
return rv;
|
|
}
|
|
public static String[] Ary_parse(String raw, String dlm) {return String_.Split(raw, dlm);}
|
|
public static String[] Ary(byte[]... ary) {
|
|
if (ary == null) return String_.Ary_empty;
|
|
int ary_len = ary.length;
|
|
String[] rv = new String[ary_len];
|
|
for (int i = 0; i < ary_len; i++) {
|
|
byte[] itm = ary[i];
|
|
rv[i] = itm == null ? null : String_.new_u8(itm);
|
|
}
|
|
return rv;
|
|
}
|
|
public static String [] Ary_filter(String[] src, String[] filter) {
|
|
Hash_adp hash = Hash_adp_.New();
|
|
int len = filter.length;
|
|
for (int i = 0; i < len; i++) {
|
|
String itm = filter[i];
|
|
hash.Add_if_dupe_use_nth(itm, itm);
|
|
}
|
|
List_adp rv = List_adp_.New();
|
|
len = src.length;
|
|
for (int i = 0; i < len; i++) {
|
|
String itm = src[i];
|
|
if (hash.Has(itm)) rv.Add(itm);
|
|
}
|
|
return rv.To_str_ary();
|
|
}
|
|
public static String[] Ary_flatten(String[][] src_ary) {
|
|
int trg_len = 0;
|
|
int src_len = Array_.Len(src_ary);
|
|
for (int i = 0; i < src_len; i++) {
|
|
String[] itm = src_ary[i];
|
|
if (itm != null) trg_len += Array_.Len(itm);
|
|
}
|
|
String[] trg_ary = new String[trg_len];
|
|
trg_len = 0;
|
|
for (int i = 0; i < src_len; i++) {
|
|
String[] itm = src_ary[i];
|
|
if (itm == null) continue;
|
|
int itm_len = Array_.Len(itm);
|
|
for (int j = 0; j < itm_len; j++)
|
|
trg_ary[trg_len++] = itm[j];
|
|
}
|
|
return trg_ary;
|
|
}
|
|
public static boolean Ary_eq(String[] lhs, String[] rhs) {
|
|
int lhs_len = lhs.length, rhs_len = rhs.length;
|
|
if (lhs_len != rhs_len) return false;
|
|
for (int i = 0; i < lhs_len; ++i)
|
|
if (!String_.Eq(lhs[i], rhs[i])) return false;
|
|
return true;
|
|
}
|
|
public static String To_str__as_kv_ary(String... ary) {
|
|
int len = ary.length;
|
|
Bry_bfr bfr = Bry_bfr_.New();
|
|
for (int i = 0; i < len; i+=2) {
|
|
bfr.Add_str_u8(ary[i]).Add_byte_eq();
|
|
String val = i + 1 < len ? ary[i + 1] : null;
|
|
if (val != null) bfr.Add_str_u8(val);
|
|
bfr.Add_byte_nl();
|
|
}
|
|
return bfr.To_str_and_clear();
|
|
}
|
|
}
|