android.text.SpannableStringBuilder#length ( )源码实例Demo

下面列出了android.text.SpannableStringBuilder#length ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。

源代码1 项目: OpenHub   文件: ViewUtils.java
@NonNull
public static SpannableStringBuilder getLabelsSpan(@NonNull Context context,
                                                   @Nullable ArrayList<Label> labels){
    SpannableStringBuilder labelsText  = new SpannableStringBuilder("");
    if(labels == null){
        return labelsText;
    }
    int start;
    for(int i = 0; i < labels.size(); i++){
        Label label = labels.get(i);
        start = labelsText.length();
        labelsText.append(label.getName());
        labelsText.setSpan(new IssueLabelSpan(context, label), start, start + label.getName().length(), 0);
    }
    return labelsText;
}
 
源代码2 项目: Maying   文件: ProfileManagerActivity.java
public void updateText(boolean isShowUrl) {
    final SpannableStringBuilder builder = new SpannableStringBuilder();
    builder.append(this.item.url_group).append("\n");
    if (isShowUrl) {
        int start = builder.length();
        builder.append(this.item.url);
        builder.setSpan(new TextAppearanceSpan(ProfileManagerActivity.this, android.R.style.TextAppearance_Small),
                start,
                builder.length(),
                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
    handler.post(new Runnable() {
        @Override
        public void run() {
            text.setText(builder);
        }
    });
}
 
private CharSequence prepareMainMessageString(final PermissionDialogDelegate delegate) {
    SpannableStringBuilder fullString = new SpannableStringBuilder();

    String messageText = delegate.getMessageText();
    String linkText = delegate.getLinkText();
    if (!TextUtils.isEmpty(messageText)) fullString.append(messageText);

    // If the linkText exists, then wrap it in a clickable span and concatenate it with the main
    // dialog message.
    if (!TextUtils.isEmpty(linkText)) {
        if (fullString.length() > 0) fullString.append(" ");
        int spanStart = fullString.length();

        fullString.append(linkText);
        fullString.setSpan(new ClickableSpan() {
            @Override
            public void onClick(View view) {
                mDecision = NOT_DECIDED;
                delegate.onLinkClicked();
                if (mDialog != null) mDialog.dismiss();
            }
        }, spanStart, fullString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    return fullString;
}
 
源代码4 项目: dante   文件: ImgListener.java
@Override
public void start(Block block, SpannableStringBuilder text) {
    String src = ((HtmlBlock) block).getAttributes().get(ATTRIBUTE_SRC);
    if (src == null) {
        return;
    }

    int originalLength = text.length();
    text.append(UNICODE_REPLACE);
    Drawable image = imgLoader.loadImage(src);
    text.setSpan(
            new ImageSpan(image, src),
            originalLength,
            text.length(),
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
    );
}
 
源代码5 项目: jianshi   文件: SettingActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  JianShiApplication.getAppComponent().inject(this);
  setContentView(R.layout.activity_setting);
  verticalWrite.setChecked(userPrefs.getVerticalWrite());
  homeImagePoemSwitch.setChecked(userPrefs.getHomeImagePoemSetting());
  Blaster.log(LoggingData.PAGE_IMP_SETTING);

  SpannableStringBuilder builder = new SpannableStringBuilder();
  builder.append(getString(R.string.version_upgrade));
  builder.append(". ");
  int length = builder.length();
  builder.append(getString(R.string.current_version_code));
  builder.append(BuildConfig.VERSION_NAME);
  builder.setSpan(new RelativeSizeSpan(10f), length, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
  versionUgradeTitle.setText(builder.toString());
  setupUpgradeWarning();
}
 
源代码6 项目: kaif-android   文件: Emitter.java
private void emitCodeLines(final SpannableStringBuilder out,
    final Line lines,
    final String meta) {
  if (out.length() != 0) {
    out.append("\n\n");
  }
  this.config.decorator.openCodeBlock(out);
  StringBuilder builder = new StringBuilder();
  Line line = lines;
  while (line != null) {
    if (line.isEmpty) {
      builder.append("\n");
    } else {
      builder.append(line.value).append("\n");
    }
    line = line.next;
  }
  out.append(builder.deleteCharAt(builder.length() - 1).toString());
  this.config.decorator.closeCodeBlock(out);
}
 
源代码7 项目: delion   文件: PaymentRequestSection.java
/**
 * Builds a CharSequence that displays a value in a particular currency.
 *
 * @param currency    Currency of the value being displayed.
 * @param value       Value to display.
 * @param isValueBold Whether or not to bold the item.
 * @return CharSequence that represents the whole value.
 */
private CharSequence createValueString(String currency, String value, boolean isValueBold) {
    SpannableStringBuilder valueBuilder = new SpannableStringBuilder();
    valueBuilder.append(currency);
    valueBuilder.append(" ");

    int boldStartIndex = valueBuilder.length();
    valueBuilder.append(value);

    if (isValueBold) {
        valueBuilder.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), boldStartIndex,
                boldStartIndex + value.length(), 0);
    }

    return valueBuilder;
}
 
源代码8 项目: drawee-text-view   文件: MainActivity.java
CharSequence buildText2() {
    SpannableStringBuilder builder = new SpannableStringBuilder();
    builder.append("Reset text in same DraweeTextView~~~~");
    int start = builder.length();
    builder.append("[img]");
    builder.setSpan(new DraweeSpan.Builder("http://img.yo9.com/24fe1ed09fbc11e59d8700163e00043c")
                    .setLayout(50, 50).build(),
            start, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    builder.append("\n\n");
    builder.append("This is a gif, margin=10:");
    start = builder.length();
    builder.append("[gif:d559f520246811e69a4a00163e000cdb]");
    Drawable placeHolder = new ColorDrawable(Color.BLUE);
    builder.setSpan(new DraweeSpan.Builder("http://img.yo9.com/d559f520246811e69a4a00163e000cdb")
                    .setPlaceHolderImage(placeHolder)
                    .setLayout(200, 197)
                    .setMargin(10)
                    .setShowAnimaImmediately(true)
                    .build(),
            start, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    builder.append("\n\n");
    start = builder.length();
    builder.append("[emotion:tv_cheers]");
    builder.setSpan(new DraweeSpan.Builder("http://static.yo9.com/web/emotions/tv_cheers.png").build()
            , start, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    builder.append("bilibili- ( ゜- ゜)つロ 乾杯~\n");
    return builder;
}
 
源代码9 项目: K-Sonic   文件: WebvttCueParser.java
private static void applySpansForTag(String cueId, StartTag startTag, SpannableStringBuilder text,
    List<WebvttCssStyle> styles, List<StyleMatch> scratchStyleMatches) {
  int start = startTag.position;
  int end = text.length();
  switch(startTag.name) {
    case TAG_BOLD:
      text.setSpan(new StyleSpan(STYLE_BOLD), start, end,
          Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
      break;
    case TAG_ITALIC:
      text.setSpan(new StyleSpan(STYLE_ITALIC), start, end,
          Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
      break;
    case TAG_UNDERLINE:
      text.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
      break;
    case TAG_CLASS:
    case TAG_LANG:
    case TAG_VOICE:
    case "": // Case of the "whole cue" virtual tag.
      break;
    default:
      return;
  }
  scratchStyleMatches.clear();
  getApplicableStyles(styles, cueId, startTag, scratchStyleMatches);
  int styleMatchesCount = scratchStyleMatches.size();
  for (int i = 0; i < styleMatchesCount; i++) {
    applyStyleToText(text, scratchStyleMatches.get(i).style, start, end);
  }
}
 
源代码10 项目: Telegram   文件: ThemeEditorView.java
public CharSequence generateSearchName(String name, String q) {
    if (TextUtils.isEmpty(name)) {
        return "";
    }
    SpannableStringBuilder builder = new SpannableStringBuilder();
    String wholeString = name.trim();
    String lower = wholeString.toLowerCase();

    int index;
    int lastIndex = 0;
    while ((index = lower.indexOf(q, lastIndex)) != -1) {
        int end = q.length() + index;

        if (lastIndex != 0 && lastIndex != index + 1) {
            builder.append(wholeString.substring(lastIndex, index));
        } else if (lastIndex == 0 && index != 0) {
            builder.append(wholeString.substring(0, index));
        }

        String query = wholeString.substring(index, Math.min(wholeString.length(), end));
        if (query.startsWith(" ")) {
            builder.append(" ");
        }
        query = query.trim();

        int start = builder.length();
        builder.append(query);
        builder.setSpan(new ForegroundColorSpan(0xff4d83b3), start, start + query.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        lastIndex = end;
    }

    if (lastIndex != -1 && lastIndex < wholeString.length()) {
        builder.append(wholeString.substring(lastIndex));
    }

    return builder;
}
 
源代码11 项目: SDHtmlTextView   文件: StyledTextHandler.java
@Override
public void beforeChildren(TagNode node, SpannableStringBuilder builder, SpanStack spanStack) {

    Style useStyle = spanStack.getStyle( node, getStyle() );

    if (builder.length() > 0 &&  useStyle.getDisplayStyle() == Style.DisplayStyle.BLOCK ) {

        if ( builder.charAt(builder.length() -1) != '\n' ) {
            builder.append('\n');
        }
    }

    //If we have a top margin, we insert an extra newline. We'll manipulate the line height
    //of this newline to create the margin.
    if ( useStyle.getMarginTop() != null ) {

        StyleValue styleValue = useStyle.getMarginTop();

        if ( styleValue.getUnit() == StyleValue.Unit.PX ) {
            if ( styleValue.getIntValue() > 0 ) {
                if ( appendNewLine(builder) ) {
                    spanStack.pushSpan( new VerticalMarginSpan( styleValue.getIntValue() ),
                        builder.length() -1, builder.length() );
                }
            }
        } else {
            if ( styleValue.getFloatValue() > 0f ) {
                if ( appendNewLine(builder) ) {
                    spanStack.pushSpan( new VerticalMarginSpan( styleValue.getFloatValue() ),
                        builder.length() -1, builder.length() );
                }
            }
        }

    }


}
 
源代码12 项目: Silence   文件: RecipientsEditor.java
public void populate(Recipients list) {
    SpannableStringBuilder sb = new SpannableStringBuilder();

    for (Recipient c : list.getRecipientsList()) {
        if (sb.length() != 0) {
            sb.append(", ");
        }

        sb.append(contactToToken(c));
    }

    setText(sb);
}
 
源代码13 项目: AndroidChromium   文件: AnswerTextBuilder.java
/**
 * Append the styled text in textField to the supplied builder.
 *
 * @param builder The builder to append the text to.
 * @param textField The text field (with text and type) to append.
 * @param maxTextHeightSp The height in SP of the largest text field in the entire line. Used to
 *                        top-align text when specified.
 * @param metrics Font metrics which will be used to properly size and layout images and top-
 *                aligned text.
 * @param density Screen density which will be used to properly size and layout images and top-
 *                aligned text.
*/
private static void appendAndStyleText(
        SpannableStringBuilder builder, SuggestionAnswer.TextField textField,
        int maxTextHeightSp, Paint.FontMetrics metrics, float density) {
    String text = textField.getText();
    int type = textField.getType();

    // Unescape HTML entities (e.g. "&quot;", "&gt;").
    text = Html.fromHtml(text).toString();

    // Append as HTML (answer responses contain simple markup).
    int start = builder.length();
    builder.append(Html.fromHtml(text));
    int end = builder.length();

    // Apply styles according to the type.
    AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(getAnswerTextSizeSp(type), true);
    builder.setSpan(sizeSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

    ForegroundColorSpan colorSpan = new ForegroundColorSpan(getAnswerTextColor(type));
    builder.setSpan(colorSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

    if (type == ANSWERS_TOP_ALIGNED_TEXT_TYPE) {
        TopAlignedSpan topAlignedSpan =
                new TopAlignedSpan(
                        ANSWERS_TOP_ALIGNED_TEXT_SIZE_SP, maxTextHeightSp, metrics, density);
        builder.setSpan(topAlignedSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
}
 
源代码14 项目: EhViewer   文件: Html.java
private static void end(SpannableStringBuilder text, Class kind,
        Object repl) {
    int len = text.length();
    Object obj = getLast(text, kind);
    int where = text.getSpanStart(obj);

    text.removeSpan(obj);

    if (where != len) {
        text.setSpan(repl, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
}
 
源代码15 项目: Dashchan   文件: ContentsFragment.java
private CharSequence makeSubdirDescrption() {
	String[] formats = {"\\c", "\\d", "\\b", "\\t", "\\e", "<\u2026>"};
	String[] descriptions = getResources().getStringArray(R.array.preference_subdirectory_pattern_descriptions);
	SpannableStringBuilder builder = new SpannableStringBuilder();
	for (int i = 0; i < formats.length; i++) {
		if (builder.length() > 0) {
			builder.append('\n');
		}
		StringUtils.appendSpan(builder, formats[i], new TypefaceSpan("sans-serif-medium"));
		builder.append(" — ");
		builder.append(descriptions[i]);
	}
	return builder;
}
 
源代码16 项目: 365browser   文件: PaymentRequestSection.java
private CharSequence convertOptionToString(
        PaymentOption item, boolean useBoldLabel, boolean singleLine) {
    SpannableStringBuilder builder = new SpannableStringBuilder(item.getLabel());
    String labelSeparator = singleLine
            ? getContext().getString(R.string.autofill_address_summary_separator)
            : "\n";
    if (useBoldLabel) {
        builder.setSpan(
                new StyleSpan(android.graphics.Typeface.BOLD), 0, builder.length(), 0);
    }

    if (!TextUtils.isEmpty(item.getSublabel())) {
        if (builder.length() > 0) builder.append(labelSeparator);
        builder.append(item.getSublabel());
    }

    if (!TextUtils.isEmpty(item.getTertiaryLabel())) {
        if (builder.length() > 0) builder.append(labelSeparator);
        builder.append(item.getTertiaryLabel());
    }

    if (!item.isComplete() && !TextUtils.isEmpty(item.getEditMessage())) {
        if (builder.length() > 0) builder.append(labelSeparator);
        String editMessage = item.getEditMessage();
        builder.append(editMessage);
        Object foregroundSpanner = new ForegroundColorSpan(ApiCompatibilityUtils.getColor(
                getContext().getResources(), R.color.google_blue_700));
        Object sizeSpanner = new AbsoluteSizeSpan(14, true);
        int startIndex = builder.length() - editMessage.length();
        builder.setSpan(foregroundSpanner, startIndex, builder.length(), 0);
        builder.setSpan(sizeSpanner, startIndex, builder.length(), 0);
    }

    return builder;
}
 
源代码17 项目: Dashchan   文件: PostItem.java
private CharSequence makeFullName() {
	String name = post.getName();
	String identifier = post.getIdentifier();
	String tripcode = post.getTripcode();
	String capcode = post.getCapcode();
	String defaultName = ChanConfiguration.get(getChanName()).getDefaultName(boardName);
	if (StringUtils.isEmptyOrWhitespace(defaultName)) {
		defaultName = "Anonymous";
	}
	if (StringUtils.isEmptyOrWhitespace(name)) {
		name = defaultName;
	} else {
		name = name.trim();
	}
	boolean useDefaultName = post.isDefaultName() || name.equals(defaultName);
	boolean hasIdentifier = !StringUtils.isEmptyOrWhitespace(identifier);
	boolean hasTripcode = !StringUtils.isEmptyOrWhitespace(tripcode);
	boolean hasCapcode = !StringUtils.isEmptyOrWhitespace(capcode);
	CharSequence fullName;
	if (hasIdentifier || hasTripcode || hasCapcode) {
		SpannableStringBuilder spannable = new SpannableStringBuilder();
		if (!useDefaultName) {
			spannable.append(name);
		}
		if (hasIdentifier) {
			if (spannable.length() > 0) {
				spannable.append(' ');
			}
			StringUtils.appendSpan(spannable, identifier, new NameColorSpan(NameColorSpan.TYPE_TRIPCODE));
		}
		if (hasTripcode) {
			if (spannable.length() > 0) {
				spannable.append(' ');
			}
			StringUtils.appendSpan(spannable, tripcode, new NameColorSpan(NameColorSpan.TYPE_TRIPCODE));
		}
		if (hasCapcode) {
			if (spannable.length() > 0) {
				spannable.append(' ');
			}
			StringUtils.appendSpan(spannable, "## " + capcode, new NameColorSpan(NameColorSpan.TYPE_CAPCODE));
		}
		fullName = spannable;
		useDefaultName = false;
	} else {
		fullName = name;
	}
	this.useDefaultName = useDefaultName;
	return fullName;
}
 
源代码18 项目: VideoOS-Android-SDK   文件: UDSpannableString.java
private void initSpannableStringBuilder(LuaValue text, LuaValue config) {
    SpannableStringBuilder spannableStringBuilder = getSpannableStringBuilder();
    if (text != null && text.isstring()) {
        spannableStringBuilder = spannableStringBuilder.append(text.tojstring());
    }

    if (spannableStringBuilder.length() > 0) {
        if (config != null && config.istable()) {
             int end = spannableStringBuilder.length();
             int fontSize = DimenUtil.spToPx(config.get("fontSize").optint(-1));
             Integer fontColor = ColorUtil.parse(LuaUtil.getValue(config, "fontColor"));
             String fontName = config.get("fontName").optjstring(null);

             LuaValue weightValue = config.get("fontWeight");
             int fontWeight = LuaUtil.isNumber(weightValue) ? weightValue.optint(UDFontWeight.WEIGHT_NORMAL_INT) : UDFontWeight.getValue(weightValue.optjstring(UDFontWeight.WEIGHT_NORMAL));

             LuaValue styleValue = config.get("fontStyle");
             int fontStyle = LuaUtil.isNumber(styleValue) ? styleValue.optint(Typeface.NORMAL) : UDFontStyle.getValue(styleValue.optjstring(UDFontStyle.STYLE_NORMAL));

             Integer backgroundColor = ColorUtil.parse(LuaUtil.getValue(config, "backgroundColor"));
             boolean strikethrough = config.get("strikethrough").optboolean(false);
             boolean underline = config.get("underline").optboolean(false);

            if (fontSize != -1) {//字体大小
                spannableStringBuilder.setSpan(new AbsoluteSizeSpan(fontSize), 0, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }

            if (fontColor != null) {//字体颜色
                spannableStringBuilder.setSpan(new ForegroundColorSpan(fontColor), 0, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }

            if (fontName != null && getLuaResourceFinder() != null) {//字体
                spannableStringBuilder.setSpan(new CustomTypefaceSpan(fontName, getLuaResourceFinder().findTypeface(fontName)), 0, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }

            if (fontWeight != -1 && fontWeight > UDFontWeight.WEIGHT_NORMAL_INT) {//文字Weight
                spannableStringBuilder.setSpan(new WeightStyleSpan(fontWeight), 0, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }

            if (fontStyle != -1 && (fontStyle >= Typeface.NORMAL && fontStyle <= Typeface.BOLD_ITALIC)) {//文字样式
                spannableStringBuilder.setSpan(new StyleSpan(fontStyle), 0, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }

            if (backgroundColor != null) {//背景色
                spannableStringBuilder.setSpan(new BackgroundColorSpan(backgroundColor), 0, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }

            if (strikethrough) {//删除线
                spannableStringBuilder.setSpan(new StrikethroughSpan(), 0, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }

            if (underline) {//下划线
                spannableStringBuilder.setSpan(new UnderlineSpan(), 0, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    }
}
 
源代码19 项目: TelePlus-Android   文件: Cea608Decoder.java
public SpannableString buildSpannableString() {
  SpannableStringBuilder builder = new SpannableStringBuilder(captionStringBuilder);
  int length = builder.length();

  int underlineStartPosition = C.INDEX_UNSET;
  int italicStartPosition = C.INDEX_UNSET;
  int colorStartPosition = 0;
  int color = Color.WHITE;

  boolean nextItalic = false;
  int nextColor = Color.WHITE;

  for (int i = 0; i < cueStyles.size(); i++) {
    CueStyle cueStyle = cueStyles.get(i);
    boolean underline = cueStyle.underline;
    int style = cueStyle.style;
    if (style != STYLE_UNCHANGED) {
      // If the style is a color then italic is cleared.
      nextItalic = style == STYLE_ITALICS;
      // If the style is italic then the color is left unchanged.
      nextColor = style == STYLE_ITALICS ? nextColor : STYLE_COLORS[style];
    }

    int position = cueStyle.start;
    int nextPosition = (i + 1) < cueStyles.size() ? cueStyles.get(i + 1).start : length;
    if (position == nextPosition) {
      // There are more cueStyles to process at the current position.
      continue;
    }

    // Process changes to underline up to the current position.
    if (underlineStartPosition != C.INDEX_UNSET && !underline) {
      setUnderlineSpan(builder, underlineStartPosition, position);
      underlineStartPosition = C.INDEX_UNSET;
    } else if (underlineStartPosition == C.INDEX_UNSET && underline) {
      underlineStartPosition = position;
    }
    // Process changes to italic up to the current position.
    if (italicStartPosition != C.INDEX_UNSET && !nextItalic) {
      setItalicSpan(builder, italicStartPosition, position);
      italicStartPosition = C.INDEX_UNSET;
    } else if (italicStartPosition == C.INDEX_UNSET && nextItalic) {
      italicStartPosition = position;
    }
    // Process changes to color up to the current position.
    if (nextColor != color) {
      setColorSpan(builder, colorStartPosition, position, color);
      color = nextColor;
      colorStartPosition = position;
    }
  }

  // Add any final spans.
  if (underlineStartPosition != C.INDEX_UNSET && underlineStartPosition != length) {
    setUnderlineSpan(builder, underlineStartPosition, length);
  }
  if (italicStartPosition != C.INDEX_UNSET && italicStartPosition != length) {
    setItalicSpan(builder, italicStartPosition, length);
  }
  if (colorStartPosition != length) {
    setColorSpan(builder, colorStartPosition, length, color);
  }

  return new SpannableString(builder);
}
 
源代码20 项目: Telegram-FOSS   文件: TtmlNode.java
private SpannableStringBuilder cleanUpText(SpannableStringBuilder builder) {
  // Having joined the text elements, we need to do some final cleanup on the result.
  // 1. Collapse multiple consecutive spaces into a single space.
  int builderLength = builder.length();
  for (int i = 0; i < builderLength; i++) {
    if (builder.charAt(i) == ' ') {
      int j = i + 1;
      while (j < builder.length() && builder.charAt(j) == ' ') {
        j++;
      }
      int spacesToDelete = j - (i + 1);
      if (spacesToDelete > 0) {
        builder.delete(i, i + spacesToDelete);
        builderLength -= spacesToDelete;
      }
    }
  }
  // 2. Remove any spaces from the start of each line.
  if (builderLength > 0 && builder.charAt(0) == ' ') {
    builder.delete(0, 1);
    builderLength--;
  }
  for (int i = 0; i < builderLength - 1; i++) {
    if (builder.charAt(i) == '\n' && builder.charAt(i + 1) == ' ') {
      builder.delete(i + 1, i + 2);
      builderLength--;
    }
  }
  // 3. Remove any spaces from the end of each line.
  if (builderLength > 0 && builder.charAt(builderLength - 1) == ' ') {
    builder.delete(builderLength - 1, builderLength);
    builderLength--;
  }
  for (int i = 0; i < builderLength - 1; i++) {
    if (builder.charAt(i) == ' ' && builder.charAt(i + 1) == '\n') {
      builder.delete(i, i + 1);
      builderLength--;
    }
  }
  // 4. Trim a trailing newline, if there is one.
  if (builderLength > 0 && builder.charAt(builderLength - 1) == '\n') {
    builder.delete(builderLength - 1, builderLength);
    /*builderLength--;*/
  }
  return builder;
}