view src/goodjava/bbcode/BBCode.java @ 1737:6c9aea554691

generalize bbcode
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 18 Oct 2022 22:08:29 -0600
parents 31a82b0d0a87
children
line wrap: on
line source

package goodjava.bbcode;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.regex.Pattern;
import goodjava.parser.Parser;


public final class BBCode {

	private static final Pattern tagPtn = Pattern.compile(
		"\\[(/?[a-zA-Z_]+(=[^ \\n\\t\\[\\]]*)?)\\]"
	);

	public static String encode(String s) {
		return tagPtn.matcher(s).replaceAll("[brackets]$1[/brackets]");
	}


	public final class Element {
		public final String name;
		public final String param;
		public final Object contents;  // String, Element, or List

		private Element(String name,String param,Object contents) {
			this.name = name.toLowerCase();
			this.param = param;
			this.contents = contents;
		}
	}

	public static Object parse(String text) {
		if( text.indexOf('[') == -1 )
			return text;
		return new BBCode(text).parse();
	}

	private final Parser parser;

	private BBCode(String text) {
		this.parser = new Parser(text);
	}

	private Object parse() {
		List list = new ArrayList();
		StringBuilder text = new StringBuilder();
		while( !parser.endOfInput() ) {
			Element block = parseBlock();
			if( block != null ) {
				add(list,text);
				list.add( block );
			} else {
				text.append( parser.currentChar() );
				parser.anyChar();
			}
		}
		add(list,text);
		return list.size()==1 ? list.get(0) : list;
	}

	private Object parseUntil(String end) {
		List list = new ArrayList();
		StringBuilder text = new StringBuilder();
		while( !parser.matchIgnoreCase(end) ) {
			if( parser.endOfInput() )
				return null;
			Element block = parseBlock();
			if( block != null ) {
				add(list,text);
				list.add( block );
			} else {
				text.append( parser.currentChar() );
				parser.anyChar();
			}
		}
		add(list,text);
		return list.size()==1 ? list.get(0) : list;
	}

	private void add(List list,StringBuilder text) {
		if( text.length() > 0 ) {
			list.add( text.toString() );
			text.setLength(0);
		}
	}

	private Element parseBlock() {
		if( parser.currentChar() != '[' )
			return null;
		parser.begin();
		parser.anyChar();  // [
		int start = parser.currentIndex();
		if( !matchTagChar() )
			return parser.failure(null);
		while(matchTagChar());
		String name = parser.textFrom(start).toLowerCase();
		String param = null;
		if( parser.match('=') ) {
			start = parser.currentIndex();
			while( parser.noneOf("[]\n") );
			param = parser.textFrom(start);
		}
		if( !parser.match(']') )
			return parser.failure(null);
		Object content = parseUntil("[/"+name+"]");
		if( content==null )
			return parser.failure(null);
		Element rtn = new Element(name,param,content);
		return parser.success(rtn);
	}

	private boolean matchTagChar() {
		return parser.inCharRange('a','z')
			|| parser.inCharRange('A','Z')
			|| parser.inCharRange('0','9')
			|| parser.match('_')
		;
	}

}