2003-08-10 19:30:07 +00:00
|
|
|
/*
|
|
|
|
The contents of this file are subject to the THDL Open Community License
|
|
|
|
Version 1.0 (the "License"); you may not use this file except in compliance
|
|
|
|
with the License. You may obtain a copy of the License on the THDL web site
|
|
|
|
(http://www.thdl.org/).
|
|
|
|
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
|
|
|
License for the specific terms governing rights and limitations under the
|
|
|
|
License.
|
|
|
|
|
|
|
|
The Initial Developer of this software is the Tibetan and Himalayan Digital
|
|
|
|
Library (THDL). Portions created by the THDL are Copyright 2003 THDL.
|
|
|
|
All Rights Reserved.
|
|
|
|
|
|
|
|
Contributor(s): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.thdl.tib.text.ttt;
|
|
|
|
|
|
|
|
import org.thdl.util.ThdlDebug;
|
|
|
|
|
2005-02-21 01:16:10 +00:00
|
|
|
/** An ordered pair used in ACIP/EWTS-to-TMW/Unicode conversion. The
|
|
|
|
* left side is the consonant or empty; the right side is either the
|
2005-02-22 04:36:54 +00:00
|
|
|
* vowel or '+' (indicating stacking in both ACIP and EWTS) or a
|
|
|
|
* disambiguator (e.g., '-' in ACIP or '.' in EWTS).
|
2003-08-10 19:30:07 +00:00
|
|
|
* @author David Chandler */
|
2005-02-21 01:16:10 +00:00
|
|
|
/* BIG FIXME: make this package work for EWTS, not just ACIP. (TODO(DLC)[EWTS->Tibetan]: does it?) */
|
2003-08-10 19:30:07 +00:00
|
|
|
class TPair {
|
2005-02-22 04:36:54 +00:00
|
|
|
/** the part that knows ACIP from EWTS */
|
|
|
|
private TTraits traits;
|
|
|
|
|
|
|
|
/** Returns the part that knows ACIP from EWTS. */
|
|
|
|
public TTraits getTraits() { return traits; }
|
|
|
|
|
|
|
|
/** The left side, or null if there is no left side. I.e., the
|
|
|
|
* non-wowel, non-disambiguator, non-'+' guy. */
|
2003-08-10 19:30:07 +00:00
|
|
|
private String l;
|
|
|
|
String getLeft() {
|
|
|
|
ThdlDebug.verify(!"".equals(l));
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
2005-02-22 04:36:54 +00:00
|
|
|
/** The right side. That is, the wowel or disambiguator or "+"
|
|
|
|
* (for stacking) or null otherwise. */
|
2003-08-10 19:30:07 +00:00
|
|
|
private String r;
|
|
|
|
String getRight() {
|
|
|
|
ThdlDebug.verify(!"".equals(r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Constructs a new TPair with left side l and right side r.
|
|
|
|
* Use null or the empty string to represent an absence. */
|
2005-02-22 04:36:54 +00:00
|
|
|
TPair(TTraits traits, String l, String r) {
|
2003-08-10 19:30:07 +00:00
|
|
|
// Normalize:
|
|
|
|
if (null != l && l.equals("")) l = null;
|
|
|
|
if (null != r && r.equals("")) r = null;
|
|
|
|
|
|
|
|
this.l = l;
|
|
|
|
this.r = r;
|
2005-02-22 04:36:54 +00:00
|
|
|
this.traits = traits;
|
2003-08-10 19:30:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns a nice String representation. Returns "(D . E)" for
|
|
|
|
* ACIP {DE}, e.g., and (l . r) in general. */
|
|
|
|
public String toString() {
|
|
|
|
return "("
|
|
|
|
+ ((null == l) ? "" : l) + " . "
|
|
|
|
+ ((null == r) ? "" : r) + ")";
|
|
|
|
}
|
|
|
|
|
2005-02-22 04:36:54 +00:00
|
|
|
/** Returns the number of transliteration characters that make up
|
|
|
|
* this TPair. */
|
2003-08-10 19:30:07 +00:00
|
|
|
int size() {
|
|
|
|
return (((l == null) ? 0 : l.length())
|
|
|
|
+ ((r == null) ? 0 : r.length()));
|
|
|
|
}
|
|
|
|
|
2005-02-21 01:16:10 +00:00
|
|
|
/** Returns a TPair that is like this one except that it is
|
2003-08-10 19:30:07 +00:00
|
|
|
* missing N characters. The characters are taken from r, the
|
2003-08-31 16:06:35 +00:00
|
|
|
* right side, first and from l, the left side, second. The pair
|
|
|
|
* returned may be illegal, such as the (A . ') you can get from
|
|
|
|
* ACIP {A'AAMA}.
|
2003-09-10 01:19:05 +00:00
|
|
|
* @throws IllegalArgumentException if N is out of range */
|
2005-02-21 01:16:10 +00:00
|
|
|
TPair minusNRightmostTransliterationCharacters(int N)
|
2003-08-10 19:30:07 +00:00
|
|
|
throws IllegalArgumentException
|
|
|
|
{
|
|
|
|
int sz;
|
|
|
|
String newL = l, newR = r;
|
|
|
|
if (N > size())
|
|
|
|
throw new IllegalArgumentException("Don't have that many to remove.");
|
|
|
|
if (N < 1)
|
2003-08-31 16:06:35 +00:00
|
|
|
throw new IllegalArgumentException("You shouldn't call this if you don't want to remove any.");
|
2003-08-10 19:30:07 +00:00
|
|
|
if (null != r && (sz = r.length()) > 0) {
|
|
|
|
int min = Math.min(sz, N);
|
|
|
|
newR = r.substring(0, sz - min);
|
|
|
|
N -= min;
|
|
|
|
}
|
|
|
|
if (N > 0) {
|
|
|
|
sz = l.length();
|
|
|
|
newL = l.substring(0, sz - N);
|
|
|
|
}
|
2005-02-22 04:36:54 +00:00
|
|
|
return new TPair(traits, newL, newR);
|
2003-08-10 19:30:07 +00:00
|
|
|
}
|
|
|
|
|
2005-02-22 04:36:54 +00:00
|
|
|
/** Returns true if and only if this is nonempty and if l, if
|
|
|
|
* present, is a legal consonant, and if r, if present, is a
|
|
|
|
* legal wowel. */
|
2003-08-10 19:30:07 +00:00
|
|
|
boolean isLegal() {
|
|
|
|
if (size() < 1)
|
|
|
|
return false;
|
2005-02-22 04:36:54 +00:00
|
|
|
if (null != l && !traits.isConsonant(l))
|
2003-08-10 19:30:07 +00:00
|
|
|
return false;
|
2005-02-22 04:36:54 +00:00
|
|
|
if (null != r && !traits.isWowel(r))
|
2003-08-10 19:30:07 +00:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns true if and only if this pair could be a Tibetan
|
|
|
|
* prefix. */
|
|
|
|
boolean isPrefix() {
|
|
|
|
return (null != l
|
|
|
|
&& ((null == r || "".equals(r))
|
2005-02-22 04:36:54 +00:00
|
|
|
|| traits.disambiguator().equals(r)
|
|
|
|
|| traits.aVowel().equals(r)) // FIXME: though check for BASKYABS and warn because BSKYABS is more common
|
|
|
|
&& traits.isPrefix(l));
|
2003-08-10 19:30:07 +00:00
|
|
|
}
|
|
|
|
|
2003-10-16 04:15:10 +00:00
|
|
|
/** Returns true if and only if this pair could be a Tibetan
|
2003-11-09 01:07:45 +00:00
|
|
|
* secondary suffix. */
|
2003-10-16 04:15:10 +00:00
|
|
|
boolean isPostSuffix() {
|
|
|
|
return (null != l
|
|
|
|
&& ((null == r || "".equals(r))
|
2005-02-22 04:36:54 +00:00
|
|
|
|| traits.disambiguator().equals(r)
|
|
|
|
|| traits.aVowel().equals(r)) // FIXME: though warn about GAMASA vs. GAMS
|
|
|
|
&& traits.isPostsuffix(l));
|
2003-10-16 04:15:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns true if and only if this pair could be a Tibetan
|
2005-02-22 04:36:54 +00:00
|
|
|
* suffix. */
|
2003-10-16 04:15:10 +00:00
|
|
|
boolean isSuffix() {
|
|
|
|
return (null != l
|
|
|
|
&& ((null == r || "".equals(r))
|
2005-02-22 04:36:54 +00:00
|
|
|
|| traits.disambiguator().equals(r)
|
|
|
|
|| traits.aVowel().equals(r))
|
|
|
|
&& traits.isSuffix(l));
|
2003-10-16 04:15:10 +00:00
|
|
|
}
|
|
|
|
|
2003-08-10 19:30:07 +00:00
|
|
|
/** Returns true if and only if this pair is merely a
|
|
|
|
* disambiguator. */
|
|
|
|
boolean isDisambiguator() {
|
2005-02-22 04:36:54 +00:00
|
|
|
return (traits.disambiguator().equals(r) && getLeft() == null);
|
2003-08-10 19:30:07 +00:00
|
|
|
}
|
|
|
|
|
2003-10-16 04:15:10 +00:00
|
|
|
/** Yep, this works for TPairs. */
|
|
|
|
public boolean equals(Object x) {
|
|
|
|
if (x instanceof TPair) {
|
|
|
|
TPair p = (TPair)x;
|
|
|
|
return ((getLeft() == p.getLeft() || (getLeft() != null && getLeft().equals(p.getLeft())))
|
|
|
|
|| (getRight() == p.getRight() || (getRight() != null && getRight().equals(p.getRight()))));
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-02-22 04:36:54 +00:00
|
|
|
/** Returns a TPair that is like this pair except that it has a
|
2005-07-06 02:19:38 +00:00
|
|
|
* "+" on the right if this pair is empty on the right and, when
|
|
|
|
* appropriate, is empty on the right if this pair has a
|
|
|
|
* disambiguator on the right. May return itself (but never
|
|
|
|
* mutates this instance). */
|
2003-08-10 19:30:07 +00:00
|
|
|
TPair insideStack() {
|
|
|
|
if (null == getRight())
|
2005-02-22 04:36:54 +00:00
|
|
|
return new TPair(traits, getLeft(), "+");
|
2005-07-06 02:19:38 +00:00
|
|
|
else if (traits.disambiguator().equals(getRight())
|
|
|
|
&& !traits.stackingMustBeExplicit())
|
2005-02-22 04:36:54 +00:00
|
|
|
return new TPair(traits, getLeft(), null);
|
2003-08-10 19:30:07 +00:00
|
|
|
else
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns true if this pair contains a Tibetan number. */
|
|
|
|
boolean isNumeric() {
|
2005-06-20 06:18:00 +00:00
|
|
|
if (l != null && l.length() == 1) {
|
|
|
|
char ch = l.charAt(0);
|
|
|
|
return ((ch >= '0' && ch <= '9')
|
|
|
|
|| (ch >= '\u0f18' && ch <= '\u0f33')
|
|
|
|
|| ch == '\u0f3e' || ch == '\u0f3f');
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
// TODO(DLC)[EWTS->Tibetan]: what about half-numbers?
|
2003-08-10 19:30:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
String getWylie() {
|
2005-07-06 07:46:21 +00:00
|
|
|
return getWylie(false, false);
|
2003-08-31 16:06:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns the EWTS Wylie that corresponds to this pair if
|
|
|
|
* justLeft is false, or the EWTS Wylie that corresponds to just
|
2005-07-06 07:46:21 +00:00
|
|
|
* {@link #getLeft()} if justLeft is true. If dropDisambiguator
|
|
|
|
* is true and the right component is a disambiguator, then the
|
|
|
|
* Wylie will not contain '.'.
|
2003-12-15 07:32:14 +00:00
|
|
|
*
|
|
|
|
* <p>Returns "W" for ACIP "W", "r" for ACIP "R", y for ACIP "Y",
|
|
|
|
* even though sometimes the EWTS for those is "w", "R", or "Y".
|
|
|
|
* Handle that in the caller. */
|
2005-07-06 07:46:21 +00:00
|
|
|
String getWylie(boolean justLeft, boolean dropDisambiguator) {
|
2003-08-10 19:30:07 +00:00
|
|
|
String leftWylie = null;
|
|
|
|
if (getLeft() != null) {
|
2005-02-22 04:36:54 +00:00
|
|
|
leftWylie = traits.getEwtsForConsonant(getLeft());
|
2003-08-10 19:30:07 +00:00
|
|
|
if (leftWylie == null) {
|
|
|
|
if (isNumeric())
|
|
|
|
leftWylie = getLeft();
|
|
|
|
}
|
|
|
|
}
|
2003-08-31 16:06:35 +00:00
|
|
|
if (null == leftWylie) leftWylie = "";
|
|
|
|
if (justLeft) return leftWylie;
|
2003-08-10 19:30:07 +00:00
|
|
|
String rightWylie = null;
|
2005-07-06 07:46:21 +00:00
|
|
|
if (!dropDisambiguator && traits.disambiguator().equals(getRight()))
|
2003-08-10 19:30:07 +00:00
|
|
|
rightWylie = ".";
|
|
|
|
else if ("+".equals(getRight()))
|
|
|
|
rightWylie = "+";
|
|
|
|
else if (getRight() != null)
|
2005-02-22 04:36:54 +00:00
|
|
|
rightWylie = traits.getEwtsForWowel(getRight());
|
2003-08-10 19:30:07 +00:00
|
|
|
if (null == rightWylie) rightWylie = "";
|
|
|
|
return leftWylie + rightWylie;
|
|
|
|
}
|
2003-08-18 02:38:54 +00:00
|
|
|
|
|
|
|
/** Appends legal Unicode corresponding to this (possible
|
2003-11-09 01:07:45 +00:00
|
|
|
* subscribed) pair to sb. FIXME: which normalization form,
|
2003-08-18 02:38:54 +00:00
|
|
|
* if any? */
|
|
|
|
void getUnicode(StringBuffer sb, boolean subscribed) {
|
2003-12-14 07:36:21 +00:00
|
|
|
getUnicode(sb, sb, subscribed);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Appends legal Unicode corresponding to this (possible
|
|
|
|
* subscribed) pair to consonantSB (for the non-vowel part) and
|
|
|
|
* vowelSB (for the vowelish part ({'EEm:}, e.g.). FIXME: which
|
|
|
|
* normalization form, if any? */
|
|
|
|
void getUnicode(StringBuffer consonantSB, StringBuffer vowelSB,
|
|
|
|
boolean subscribed) {
|
2003-08-18 02:38:54 +00:00
|
|
|
if (null != getLeft()) {
|
2005-02-22 04:36:54 +00:00
|
|
|
String x = traits.getUnicodeFor(getLeft(), subscribed);
|
2003-11-30 02:06:48 +00:00
|
|
|
if (null == x) throw new Error("TPair: " + getLeft() + " has no Uni");
|
2003-12-14 07:36:21 +00:00
|
|
|
consonantSB.append(x);
|
2003-08-18 02:38:54 +00:00
|
|
|
}
|
|
|
|
if (null != getRight()
|
2005-06-20 06:18:00 +00:00
|
|
|
&& !(traits.disambiguator().equals(getRight())
|
|
|
|
|| "+".equals(getRight()) || traits.aVowel().equals(getRight()))) {
|
|
|
|
String x = traits.getUnicodeForWowel(getRight());
|
2003-11-30 02:06:48 +00:00
|
|
|
if (null == x) throw new Error("TPair: " + getRight() + " has no Uni");
|
2003-12-14 07:36:21 +00:00
|
|
|
vowelSB.append(x);
|
2003-08-18 02:38:54 +00:00
|
|
|
}
|
|
|
|
}
|
2003-10-16 04:15:10 +00:00
|
|
|
|
2005-07-06 02:19:38 +00:00
|
|
|
/** For ACIP: Returns true if this pair is surely the last pair in
|
|
|
|
* an ACIP stack. Stacking continues through (* . ) and (* . +),
|
|
|
|
* but stops anywhere else.
|
|
|
|
*
|
|
|
|
* <p>For EWTS: Returns true if this pair is probably the last
|
|
|
|
* pair in an EWTS stack. For natives stacks like that found in
|
|
|
|
* [bra], this is not really true. */
|
|
|
|
boolean endsStack() {
|
|
|
|
final boolean explicitlyStacks = "+".equals(getRight());
|
|
|
|
if (!traits.stackingMustBeExplicit())
|
|
|
|
return (getRight() != null && !explicitlyStacks);
|
|
|
|
else
|
|
|
|
return (!explicitlyStacks);
|
2003-10-16 04:15:10 +00:00
|
|
|
}
|
2003-08-10 19:30:07 +00:00
|
|
|
}
|