Android string format open Source Library phrase Introduction

Source: Internet
Author: User

In the previous blog Android through the display of String.Format formatted (dynamic change) string resource, the string in the String.xml file is formatted by String.Format, this article describes an open source library phrase that can achieve the same functionality, compared to Strin G.format, formatting string codes with phrase is more readable.


First, phrase project introduction:

1, Source: Phrase Project source code is very simple, there is only one class inside: Phrase.java, the code is as follows:

/* * Copyright (C) Square, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * You are not a use this file except in compliance with the License.  * Obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * unless required by applicable Law or agreed into writing, software * Distributed under the License is distributed on a "as is" BASIS, * without Warra Nties or CONDITIONS of any KIND, either express OR implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.uperone.stringformat;import java.util.hashmap;import Java.util.hashset;import java.util.Map;import Java.util.set;import Android.app.fragment;import Android.content.context;import android.content.res.Resources; Import Android.text.spannablestringbuilder;import android.view.view;/** * A fluent API for formatting Strings. Canonical Usage: * <pre> * charsequence formatted = Phrase.from ("Hi {first_name}, you were {age} years old. ") *. put ("first_name", FirstName) *. Put ("age", age) *. format (); * </pre> * <ul> * <li>surround keys with curly braces; Use, {to escape.</li> * <li>keys start with lowercase letters followed by lowercase letters and Underscor Es.</li> * <li>spans is preserved, such as simple HTML tags found in strings.xml.</li> * <li>fail  s fast on No mismatched keys.</li> * </ul> * 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. * <p/> * The {@link #format ()} method iterates over the tokens, replacing text as it iterates. The * doubly-linked list allows each token to ask it predecessor for the expanded length.  */public Final class Phrase {/** the unmodified original pattern. */private final charsequence pattern; /** all keys parsed from the original pattern, sans braces.  */private final set<string> keys = new hashset<string> ();  Private final map<string, charsequence> keystovalues = new hashmap<string, charsequence> (); /** Cached result after replacing all keys with corresponding values.  */private charsequence formatted; /** the constructor parses the original pattern into this doubly-linked list of tokens.  */private Token head; /** when parsing, the current character.  */Private char Curchar;  private int curcharindex; /** indicates parsing is complete.  */private static final int EOF = 0;   /** * Entry point to this API.   * * @throws IllegalArgumentException If pattern contains any syntax errors.  */public static Phrase from (Fragment F, int. Patternresourceid) {return from (F.getresources (), Patternresourceid);   }/** * Entry point to this API.   * * @throws IllegalArgumentException If pattern contains any syntax errors. */public static Phrase from (View v, int patternresOurceid) {return from (V.getresources (), Patternresourceid);   }/** * Entry point to this API.   * * @throws IllegalArgumentException If pattern contains any syntax errors.  */public static Phrase from (Context C, int. Patternresourceid) {return from (C.getresources (), Patternresourceid);   }/** * Entry point to this API.   * * @throws IllegalArgumentException If pattern contains any syntax errors.  */public static Phrase from (Resources R, Int. Patternresourceid) {return from (R.gettext (Patternresourceid)); }/** * Entry point to this API;   Pattern must be non-null.   * * @throws IllegalArgumentException If pattern contains any syntax errors.  */public static Phrase from (Charsequence pattern) {return new Phrase (pattern); }/** * Replaces the given key with a non-null value.   Reuse Phrase instances and replace * keys with new values.   * * @throws IllegalArgumentException If the key is not in the pattern. */Public Phrase put (String key, charsequence value) {if (!keys.contains (key)) {throw new IllegalArgumentException ("Invalid key:" + key    );    } if (value = = null) {throw new IllegalArgumentException ("Null value for '" + key + "'");    } keystovalues.put (key, value);    Invalidate the cached formatted text.    formatted = NULL;  return this; }/** @see #put (String, charsequence) */Public Phrase put (string key, int value) {if (!keys.contains (key)) {T    Hrow New IllegalArgumentException ("Invalid key:" + key);    } keystovalues.put (Key, integer.tostring (value));    Invalidate the cached formatted text.    formatted = NULL;  return this;   }/** * Silently ignored if the key is not in the pattern. * * @see #put (String, charsequence) */Public Phrase putoptional (string key, Charsequence value) {return Keys.con Tains (key)?  Put (key, value): this; }/** @see #put (String, charsequence) */Public Phrase putoptional (string key, int value) {return keys.coNtains (key)?  Put (key, value): this;   }/** * Returns the text after replacing all keys with values.   * * @throws illegalargumentexception If any keys is not replaced.        */Public Charsequence format () {if (formatted = = NULL) {if (!keystovalues.keyset (). Containsall (keys)) {        set<string> Missingkeys = new hashset<string> (keys);        Missingkeys.removeall (Keystovalues.keyset ());      throw new IllegalArgumentException ("Missing keys:" + Missingkeys);      }//Copy the original pattern to preserve all spans, such as bold, italic, etc.      Spannablestringbuilder sb = new Spannablestringbuilder (pattern);      for (Token t = head; T! = null; t = t.next) {t.expand (SB, keystovalues);    } formatted = SB;  } return formatted; }/** * Returns the raw pattern without expanding keys; Only useful for debugging.   Does not pass * through to {@link #format ()} because doing so would drop all spans. */@Override public String toString () {return pattern.tostring ();    } Private Phrase (charsequence pattern) {Curchar = (pattern.length () > 0)? pattern.charat (0): EOF;    This.pattern = pattern;    A hand-coded lexer based on the idioms in "Building recognizers by Hand".    Http://www.antlr2.org/book/byhand.pdf.    Token prev = null;    Token Next;      while (next = token (prev))! = NULL) {//Creates a doubly-linked list of tokens starting with head.      if (head = = null) head = Next;    prev = next; }}/** Returns the next token from the input pattern, or NULL when finished parsing.    */Private token token (token prev) {if (Curchar = = EOF) {return null;      } if (Curchar = = ' {') {char Nextchar = lookahead ();      if (Nextchar = = ' {') {return leftcurlybracket (prev);      } else if (Nextchar >= ' a ' && nextchar <= ' z ') {return key (prev); } else {throw new illegalargumentexception ("unexpected character '" + Nextchar + "';    Expected key. ");}}  Return text (prev); }/** parses a key: "{Some_key}".    */Private Keytoken key (Token prev) {//Store keys as normal Strings; we don ' t want keys to contain spans.    StringBuilder sb = new StringBuilder ();    Consume the opening ' {'.    Consume ();      while (Curchar >= ' a ' && curchar <= ' z ') | | curchar = = ' _ ') {sb.append (Curchar);    Consume ();    }//Consume the closing '} '.    if (Curchar! = '} ') {throw new IllegalArgumentException ("Missing closing brace:}");    } consume ();    Disallow empty keys: {}.    if (sb.length () = = 0) {throw new IllegalArgumentException ("Empty key: {}");    } String key = Sb.tostring ();    Keys.add (key);  return new Keytoken (prev, key); }/** consumes and returns a token for a sequence of text.    */Private Texttoken text (Token prev) {int startIndex = Curcharindex;    while (Curchar! = ' {' && Curchar! = EOF) {consume (); } return new TexttoKen (prev, Curcharindex-startindex); }/** consumes and returns a token representing the consecutive curly brackets.    */Private Leftcurlybrackettoken Leftcurlybracket (Token prev) {consume ();    Consume ();  return new Leftcurlybrackettoken (prev); }/** Returns the next character in the input pattern without advancing.  */Private char lookahead () {return Curcharindex < Pattern.length ()-1? Pattern.charat (Curcharindex + 1): EOF; }/** * Advances the current character position without any error checking.   Consuming beyond the * end of the string can only be happen if this parser contains a bug.    */private void consume () {curcharindex++; Curchar = (Curcharindex = = Pattern.length ())?  EOF:pattern.charAt (Curcharindex);    } private abstract Static class Token {private final Token prev;    Private Token Next;      Protected token (token prev) {this.prev = prev;    if (prev! = null) Prev.next = this; }/** Replace text in {@code target} with thIs token ' s associated value.    */abstract void expand (Spannablestringbuilder target, map<string, charsequence> data); /** Returns The number of characters after expansion.    */abstract int getformattedlength (); /** Returns the character index after expansion.        */FINAL int getformattedstart () {if (prev = = null) {//the first token.      return 0;        } else {//recursively ask the predecessor node for the starting index.      return Prev.getformattedstart () + prev.getformattedlength (); }}}/** ordinary text between tokens.    */private static class Texttoken extends Token {private final int textLength;      Texttoken (Token prev, int textLength) {super (prev);    This.textlength = TextLength; } @Override void expand (Spannablestringbuilder target, map<string, charsequence> data) {//Don ' t alter span    s in the target.    } @Override int Getformattedlength () {return textLength; }}/** A sequence of curly brackets.    */private static class Leftcurlybrackettoken extends token {leftcurlybrackettoken (token prev) {super (prev); } @Override void expand (Spannablestringbuilder target, map<string, charsequence> data) {int start = GETFO      Rmattedstart ();    Target.replace (Start, start + 2, "{");      } @Override int Getformattedlength () {//Replace {{with {.    return 1;    }} private static class Keytoken extends Token {/** The key without {and}. */private final String key;    private charsequence value;      Keytoken (Token prev, String key) {super (prev);    This.key = key; } @Override void expand (Spannablestringbuilder target, map<string, charsequence> data) {value = Data.get (ke      y);      int replacefrom = Getformattedstart ();      ADD 2 to account for the opening and closing brackets.      int Replaceto = Replacefrom + key.length () + 2;    Target.replace (Replacefrom, Replaceto, value); } @Overrideint Getformattedlength () {//Note that value was only present after expand.      Don ' t error check because this was all/private code.    return Value.length (); }  }}


2. The principle of string formatting:

By reading the code of Phrase.java, it uses "{" and "}" to wrap the content that needs to be formatted, and then uses the key value pairs to transmit values to the content that needs to be changed, the contents of which are keyed, and the values are dynamically set, such as:

"Hi {first_name}, you is {age} years old."
We want the final display to be: "Hi Uperone, you're years old." Here the first_name and age are keys, with values of Uperone and 26.


Second, how to use:

The comments above the Phrase.java class name have already told us how to use it:

/** * A fluent API for formatting Strings.       Canonical Usage: * <pre> * charsequence formatted = Phrase.from ("Hi {first_name}, you is {age} years old.") * . put ("first_name", FirstName) *. Put ("age", age) *. format (); * </pre> * <ul> * <li>surround keys with curly braces; Use, {to escape.</li> * <li>keys start with lowercase letters followed by lowercase letters and Underscor Es.</li> * <li>spans is preserved, such as simple HTML tags found in strings.xml.</li> * <li>fail  s fast on No mismatched keys.</li> * </ul> * 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. * <p/> * The {@link #format ()} method iterates over the tokens, replacing text as it iterates. The * doubly-linked list allows each token to ask it predecessor for the expanded length. */public Final Class PhrAse 

For example:

Charsequence parsestr = Phrase.from ("Hi {first_name}, you is {age} years old"). Put ("First_Name", "Uperone"). Put ("Age", "+"). Format (); Mparsetxt.settext (PARSESTR);
It's very easy to use.



Android string format open Source Library phrase Introduction

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.