Android 文字列フォーマット用のオープンソース ライブラリであるフレーズの紹介
前回のブログでは、Android は String.format を通じて文字列リソースの表示内容をフォーマット (動的に変更) し、String.format を使用して string.xml ファイル内の文字列をフォーマットする方法を紹介しました。オープン ソース ライブラリのフレーズは、String.format と比較して、フレーズを使用して文字列コードをフォーマットする方が読みやすくなっています。
1. フレーズプロジェクトの紹介:
1. ソース コード: フレーズ プロジェクトのソース コードは非常に単純です: Phrase.java コードは次のとおりです。
リーリー
*
* - キーを中括弧で囲みます。 2 つの {{ を使用して脱出します。
* - キーは小文字で始まり、その後に小文字とアンダースコアが続きます。
* - strings.xml にある単純な HTML タグなどのスパンは保持されます。
* - キーが一致しない場合はすぐに失敗します。
*
* コンストラクターは元のパターンを解析して、{@link Token} の二重リンク リストを作成します。
* これらのトークンは元のパターンを変更しないため、スパンは維持されます。
*
* {@link #format()} メソッドはトークンを反復処理し、反復中にテキストを置き換えます。の
* 二重リンクリストでは、各トークンがその先行トークンに拡張された長さを問い合わせることができます。
*/
public 最終クラス フレーズ {
/**修正されていないオリジナルのパターン。*/
プライベート最終 CharSequence パターン。
/**すべてのキーは中括弧を除いて元のパターンから解析されます。*/
プライベート最終 Set
キー = new HashSet();
private Final Map keyToValues = new HashMap();
/**すべてのキーを対応する値に置き換えた後にキャッシュされた結果。*/
プライベート CharSequence 形式。
/**コンストラクターは、元のパターンを解析して、この二重リンクされたトークンのリストを作成します。*/
プライベートトークンヘッド。
/**解析すると、これが現在の文字になります。*/
プライベート文字 curChar;
プライベート int curCharIndex;
/**解析が完了したことを示します。*/
プライベート静的最終整数 EOF = 0;
/*** この API へのエントリ ポイント。
*
* @throws パターンに構文エラーが含まれる場合は IllegalArgumentException。*/
public static Phrase from(Fragment f, int patternResourceId) {
return from(f.getResources(), patternResourceId);
}
/*** この API へのエントリ ポイント。
*
* @throws パターンに構文エラーが含まれる場合は IllegalArgumentException。*/
public static Phrase from(View v, int patternResourceId) {
return from(v.getResources(), patternResourceId);
}
/*** この API へのエントリ ポイント。
*
* @throws パターンに構文エラーが含まれる場合は IllegalArgumentException。*/
public static Phrase from(Context c, int patternResourceId) {
return from(c.getResources(), patternResourceId);
}
/*** この API へのエントリ ポイント。
*
* @throws パターンに構文エラーが含まれる場合は IllegalArgumentException。*/
public static Phrase from(Resources r, int patternResourceId) {
return from(r.getText(patternResourceId));
}
/*** この API へのエントリ ポイント。パターンは null 以外である必要があります。
*
* @throws パターンに構文エラーが含まれる場合は IllegalArgumentException。*/
public static Phrase from(CharSequence pattern) {
新しいフレーズ(パターン)を返します。
}
/*** 指定されたキーを null 以外の値に置き換えます。 Phrase インスタンスを再利用して置き換えることができます。
* 新しい値を持つキー。
*
* キーがパターンにない場合は @throws IllegalArgumentException。*/
public Phrase put(String key, CharSequence value) {
if (!keys.contains(key)) {
throw new IllegalArgumentException("無効なキー: " + key);
}
if (値 == null) {
throw new IllegalArgumentException("Null value for '" + key + "'");
}
keyToValues.put(キー, 値);
// キャッシュされた書式設定されたテキストを無効にします。
フォーマット済み = null;
これを返します。
}
/**@#put(String, CharSequence)を参照してください。*/
public Phrase put(String key, int value) {
if (!keys.contains(key)) {
throw new IllegalArgumentException("無効なキー: " + key);
}
keyToValues.put(key, Integer.toString(value));
// キャッシュされた書式設定されたテキストを無効にします。
フォーマット済み = null;
これを返します。
}
/*** キーがパターンに含まれていない場合は、黙って無視されます。
*
* @ #put(String, CharSequence) を参照*/
public Phrase putOptional(String key, CharSequence value) {
キーを返します。含まれる(キー) ? put(キー, 値) : これ;
}
/**@#put(String, CharSequence)を参照してください。*/
public Phrase putOptional(String key, int value) {
キーを返します。含まれる(キー) ? put(キー, 値) : これ;
}
/*** すべてのキーを値に置き換えた後のテキストを返します。
*
* キーが置換されていない場合は @throws IllegalArgumentException。*/
public CharSequence format() {
if (formatted == null) {
if (!keysToValues.keySet().containsAll(keys)) {
Set missingKeys = 新しい HashSet(keys);
missingKeys.removeAll(keysToValues.keySet());
throw new IllegalArgumentException("欠落しているキー: " + missingKeys);
}
// 元のパターンをコピーして、太字、斜体などのすべてのスパンを保持します。
SpannableStringBuilder sb = 新しい SpannableStringBuilder(パターン);
for (トークン t = head; t != null; t = t.next) {
t.expand(sb, keyToValues);
}
フォーマット済み = sb;
}
フォーマットされた状態で戻ります。
}
/*** キーを展開せずに生のパターンを返します。デバッグにのみ役立ちます。通らない
* {@link #format()} まで。そうするとすべてのスパンが削除されるためです。*/
@Override public String toString() {
パターンを返します。toString();
}プライベート フレーズ(CharSequence パターン) {
curChar = (pattern.length() > 0) ? pattern.charAt(0) : EOF;
this.pattern = パターン;
// 「Building Recognizers By Hand」のイディオムに基づいて手作業でコーディングされたレクサー。
// http://www.antlr2.org/book/byhand.pdf。
前のトークン = null;
次のトークン。
while ((next = token(prev)) != null) {
// head で始まるトークンの二重リンクリストを作成します。
if (head == null) head = next;
前 = 次;
}
}
/**入力パターンから次のトークンを返すか、解析が終了したら null を返します。*/
プライベートトークン token(前のトークン) {
if (curChar == EOF) {
null を返します。
}
if (curChar == '{') {
char nextChar = lookahead();
if (nextChar == '{') {
leftCurlyBracket(前)を返します;
else if (nextChar >= 'a' && nextChar = 'a' && curChar data);
/**展開後の文字数を返します。*/
abstract int getFormattedLength();
/**展開後の文字インデックスを返します。*/
Final int getFormattedStart() {
if (prev == null) {
// 最初のトークン。
0を返します。
} それ以外 {
// 先行ノードに開始インデックスを再帰的に問い合わせます。
戻り prev.getFormattedStart() + prev.getFormattedLength();
}
}
}
/**トークン間の通常のテキスト。*/
プライベート静的クラス TextToken extends Token {
プライベートfinal int textLength;
TextToken(前のトークン, int textLength) {
スーパー(前);
this.textLength = textLength;
}
@Override void Expand(SpannableStringBuilder target, Map data) {
// ターゲット内のスパンを変更しないでください。
}
@Override int getFormattedLength() {
textLength を返します。
}
}
/**2 つの中括弧のシーケンス。*/
プライベート静的クラス LeftCurlyBracketToken extends Token {
LeftCurlyBracketToken(前のトークン) {
スーパー(前);
}
@Override void Expand(SpannableStringBuilder target, Map data) {
int start = getFormattedStart();
target.replace(start, start + 2, "{");
}
@Override int getFormattedLength() {
// と置換する {。
1を返します。
}
}
プライベート静的クラス KeyToken extends Token {
/**{ と } のないキー。*/
プライベート最終文字列キー。
プライベート CharSequence 値。
KeyToken(前のトークン, 文字列キー) {
スーパー(前);
this.key = キー;
}
@Override void expand(SpannableStringBuilder target, Map data) {
value = data.get(key);
int replaceFrom = getFormattedStart();
// Add 2 to account for the opening and closing brackets.
int replaceTo = replaceFrom + key.length() + 2;
target.replace(replaceFrom, replaceTo, value);
}
@Override int getFormattedLength() {
// Note that value is only present after expand. Don't error check because this is all
// private code.
return value.length();
}
}
}
2、字符串格式化原理:
通过阅读Phrase.java的代码可知,它用"{"和"}"将需要格式化的内容包起来,然后用键值对给需要改变的内容传值,包起来的内容为键,值为动态设置的内容,比如:
"Hi {first_name}, you are {age} years old."
ログイン後にコピー
我们要最终的显示内容为:“Hi UperOne, you are 26 years old.”这里的first_name和age是键,值为UperOne和26。
二、使用方法:
Phrase.java的类名上面的注释已经告诉了我们具体的使用方法:
/**
* A fluent API for formatting Strings. Canonical usage:
*
* CharSequence formatted = Phrase.from("Hi {first_name}, you are {age} years old.")
* .put("first_name", firstName)
* .put("age", age)
* .format();
*
ログイン後にコピー
*
* - Surround keys with curly braces; use two {{ to escape.
* - Keys start with lowercase letters followed by lowercase letters and underscores.
* - Spans are preserved, such as simple HTML tags found in strings.xml.
* - Fails fast on any mismatched keys.
*
* The constructor parses the original pattern into a doubly-linked list of {@link Token}s.
* These tokens do not modify the original pattern, thus preserving any spans.
*
* The {@link #format()} method iterates over the tokens, replacing text as it iterates. The
* doubly-linked list allows each token to ask its predecessor for the expanded length.
*/
public final class Phrase
比如:
CharSequence parseStr = Phrase.from("Hi {first_name}, you are {age} years old.")
.put("first_name", "UperOne")
.put("age", "26")
.format();
mParseTxt.setText( parseStr );
ログイン後にコピー
用起来非常简单。
http://www.bkjia.com/PHPjc/885681.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/885681.htmlTechArticleAndroid字符串格式化开源库phrase介绍 在上一篇博客Android通过String.format式化(动态改变)字符串资源的显示内容中介绍了通过String.format来式...