Mercurial Hosting > luan
view src/goodjava/bbcode/BBCode.java @ 1704:19df8abc9805
add Table.is_list
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 01 Jul 2022 15:53:03 -0600 |
parents | 3a61451f8130 |
children | a6e27c8e7ef4 |
line wrap: on
line source
package goodjava.bbcode; import java.util.List; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import goodjava.parser.Parser; public final class BBCode { public enum Target { HTML, TEXT } public interface Quoter { public String quote(Target target,String text,String param); } public static final Quoter defaultQuoter = new Quoter() { public String quote(Target target,String text,String param) { StringBuilder sb = new StringBuilder(); sb.append( "<blockquote>" ); if( param != null ) { sb.append( htmlEncode(param) ); sb.append( " wrote:\n" ); } sb.append( text ); sb.append( "</blockquote>" ); return sb.toString(); } }; public Target target = Target.HTML; public Quoter quoter = defaultQuoter; private final Parser parser; public BBCode(String text) { this.parser = new Parser(text); } public String parse() { StringBuilder sb = new StringBuilder(); StringBuilder text = new StringBuilder(); while( !parser.endOfInput() ) { String block = parseBlock(); if( block != null ) { sb.append( textToString(text) ); sb.append(block); } else { text.append( parser.currentChar() ); parser.anyChar(); } } sb.append( textToString(text) ); return sb.toString(); } private String parseWellFormed() { StringBuilder sb = new StringBuilder(); StringBuilder text = new StringBuilder(); while( !parser.endOfInput() ) { String block = parseBlock(); if( block != null ) { sb.append( textToString(text) ); sb.append(block); continue; } if( couldBeTag() ) break; text.append( parser.currentChar() ); parser.anyChar(); } sb.append( textToString(text) ); return sb.toString(); } private String textToString(StringBuilder text) { String s = text.toString(); text.setLength(0); if( target == Target.HTML ) s = htmlEncode(s); return s; } private boolean couldBeTag() { if( parser.currentChar() != '[' ) return false; return parser.testIgnoreCase("[b]") || parser.testIgnoreCase("[/b]") || parser.testIgnoreCase("[i]") || parser.testIgnoreCase("[/i]") || parser.testIgnoreCase("[u]") || parser.testIgnoreCase("[/u]") || parser.testIgnoreCase("[url]") || parser.testIgnoreCase("[url=") || parser.testIgnoreCase("[/url]") || parser.testIgnoreCase("[code]") || parser.testIgnoreCase("[/code]") || parser.testIgnoreCase("[img]") || parser.testIgnoreCase("[/img]") || parser.testIgnoreCase("[color=") || parser.testIgnoreCase("[/color]") || parser.testIgnoreCase("[size=") || parser.testIgnoreCase("[/size]") || parser.testIgnoreCase("[video]") || parser.testIgnoreCase("[/video]") || parser.testIgnoreCase("[quote]") || parser.testIgnoreCase("[quote=") || parser.testIgnoreCase("[/quote]") ; } private String parseBlock() { if( parser.currentChar() != '[' ) return null; String s; s = parseB(); if(s!=null) return s; s = parseI(); if(s!=null) return s; s = parseU(); if(s!=null) return s; s = parseUrl1(); if(s!=null) return s; s = parseUrl2(); if(s!=null) return s; s = parseCode(); if(s!=null) return s; s = parseImg(); if(s!=null) return s; s = parseColor(); if(s!=null) return s; s = parseSize(); if(s!=null) return s; s = parseVideo(); if(s!=null) return s; s = parseQuote1(); if(s!=null) return s; s = parseQuote2(); if(s!=null) return s; return null; } private String parseB() { parser.begin(); if( !parser.matchIgnoreCase("[b]") ) return parser.failure(null); String content = parseWellFormed(); if( !parser.matchIgnoreCase("[/b]") ) return parser.failure(null); String rtn = target==Target.HTML ? "<b>"+content+"</b>" : content; return parser.success(rtn); } private String parseI() { parser.begin(); if( !parser.matchIgnoreCase("[i]") ) return parser.failure(null); String content = parseWellFormed(); if( !parser.matchIgnoreCase("[/i]") ) return parser.failure(null); String rtn = target==Target.HTML ? "<i>"+content+"</i>" : content; return parser.success(rtn); } private String parseU() { parser.begin(); if( !parser.matchIgnoreCase("[u]") ) return parser.failure(null); String content = parseWellFormed(); if( !parser.matchIgnoreCase("[/u]") ) return parser.failure(null); String rtn = target==Target.HTML ? "<u>"+content+"</u>" : content; return parser.success(rtn); } private String parseUrl1() { parser.begin(); if( !parser.matchIgnoreCase("[url]") ) return parser.failure(null); String url = parseRealUrl(); if( !parser.matchIgnoreCase("[/url]") ) return parser.failure(null); String rtn = target==Target.HTML ? "<a href='" + url + "'>" + url + "</a>" : url; return parser.success(rtn); } private String parseUrl2() { parser.begin(); if( !parser.matchIgnoreCase("[url=") ) return parser.failure(null); String url = parseRealUrl(); if( !parser.match(']') ) return parser.failure(null); String content = parseWellFormed(); if( !parser.matchIgnoreCase("[/url]") ) return parser.failure(null); String rtn = target==Target.HTML ? "<a href='" + url + "'>" + content + "</a>" : content; return parser.success(rtn); } private String parseRealUrl() { parser.begin(); while( parser.match(' ') ); int start = parser.currentIndex(); if( !parser.matchIgnoreCase("http") ) return parser.failure(null); parser.matchIgnoreCase("s"); if( !parser.matchIgnoreCase("://") ) return parser.failure(null); while( parser.noneOf(" []'") ); String url = parser.textFrom(start); while( parser.match(' ') ); return parser.success(url); } private String parseCode() { parser.begin(); if( !parser.matchIgnoreCase("[code]") ) return parser.failure(null); int start = parser.currentIndex(); while( !parser.testIgnoreCase("[/code]") ) { if( !parser.anyChar() ) return parser.failure(null); } String content = parser.textFrom(start); if( !parser.matchIgnoreCase("[/code]") ) throw new RuntimeException(); String rtn = target==Target.HTML ? "<code>"+content+"</code>" : content; return parser.success(rtn); } private String parseImg() { parser.begin(); if( !parser.matchIgnoreCase("[img]") ) return parser.failure(null); String url = parseRealUrl(); if( !parser.matchIgnoreCase("[/img]") ) return parser.failure(null); String rtn = target==Target.HTML ? "<img src='" + url + "'>" : ""; return parser.success(rtn); } private String parseColor() { parser.begin(); if( !parser.matchIgnoreCase("[color=") ) return parser.failure(null); int start = parser.currentIndex(); parser.match('#'); while( parser.inCharRange('0','9') || parser.inCharRange('a','z') || parser.inCharRange('A','Z') ); String color = parser.textFrom(start); if( !parser.match(']') ) return parser.failure(null); String content = parseWellFormed(); if( !parser.matchIgnoreCase("[/color]") ) return parser.failure(null); String rtn = target==Target.HTML ? "<span style='color: "+color+"'>"+content+"</span>" : content; return parser.success(rtn); } private String parseSize() { parser.begin(); if( !parser.matchIgnoreCase("[size=") ) return parser.failure(null); int start = parser.currentIndex(); while( parser.match('.') || parser.inCharRange('0','9') ); String size = parser.textFrom(start); if( !parser.match(']') ) return parser.failure(null); String content = parseWellFormed(); if( !parser.matchIgnoreCase("[/size]") ) return parser.failure(null); String rtn = target==Target.HTML ? "<span style='font-size: "+size+"em'>"+content+"</span>" : content; return parser.success(rtn); } private static final Pattern youtubePtn1 = Pattern.compile("https://youtu.be/([a-zA-Z0-9_-]+)(?:\\?t=([0-9]+))?"); private static final Pattern youtubePtn2 = Pattern.compile("https://www.youtube.com/watch?v=([a-zA-Z0-9_-]+)(?:\\?t=([0-9]+)s)?"); private static final Pattern bitchutePtn = Pattern.compile("https://www.bitchute.com/video/([a-zA-Z0-9]+)/"); private static Matcher find(Pattern ptn,String s) { Matcher m = ptn.matcher(s); return m.find() ? m : null; } private String parseVideo() { parser.begin(); if( !parser.matchIgnoreCase("[video]") ) return parser.failure(null); String url = parseRealUrl(); if( !parser.matchIgnoreCase("[/video]") ) return parser.failure(null); if( target==Target.TEXT ) return parser.success( "" ); Matcher m; m = find(youtubePtn1,url); if( m == null ) m = find(youtubePtn2,url); if( m != null ) { StringBuilder sb = new StringBuilder(); sb.append( "<iframe width='420' height='315' src='https://www.youtube.com/embed/" ); sb.append( m.group(1) ); String t = m.group(2); if( t != null ) { sb.append( "?start=" ); sb.append( t ); } sb.append( "' frameborder='0' allowfullscreen></iframe>" ); return parser.success( sb.toString() ); } m = find(bitchutePtn,url); if( m != null ) { StringBuilder sb = new StringBuilder(); sb.append( "<iframe width='420' height='315' scrolling='no' frameborder='0' style='border: none;' src='https://www.bitchute.com/embed/" ); sb.append( m.group(1) ); sb.append( "/'></iframe>" ); return parser.success( sb.toString() ); } return parser.success( "<a href='" + url + "'>" + url + "</a>" ); } private String parseQuote1() { parser.begin(); if( !parser.matchIgnoreCase("[quote]") ) return parser.failure(null); String content = parseWellFormed(); if( !parser.matchIgnoreCase("[/quote]") ) return parser.failure(null); String rtn = quoter.quote(target,content,null); return parser.success(rtn); } private String parseQuote2() { parser.begin(); if( !parser.matchIgnoreCase("[quote=") ) return parser.failure(null); List args = new ArrayList(); int start = parser.currentIndex(); while( parser.noneOf("[]") ); String name = parser.textFrom(start).trim(); if( !parser.match(']') ) return parser.failure(null); String content = parseWellFormed(); if( !parser.matchIgnoreCase("[/quote]") ) return parser.failure(null); String rtn = quoter.quote(target,content,name); return parser.success(rtn); } public static String htmlEncode(String s) { final char[] a = s.toCharArray(); StringBuilder buf = new StringBuilder(); for( char c : a ) { switch(c) { case '&': buf.append("&"); break; case '<': buf.append("<"); break; case '>': buf.append(">"); break; case '"': buf.append("""); break; default: buf.append(c); } } return buf.toString(); } }