html富文本style转标签

一、需求

规则:

通用:

  • 所有替换针对行内样式,即:
style="font-weight: bold; font-style: italic;"
style="font-size: 24px; color: #333"
  • 分两大类:
    • 标签类
    • 样式类

具体:

  • 标签类

    • font-weight: bold; -> 此标签内部内容用 <b>...</b> 包裹,同时去掉 font-weight: bold;
    • font-style: italic; -> 此标签内部内容用 <i>...</i> 包裹,同时去掉 font-style: italic;
    • text-decoration: underline; -> 此标签内部内容用 <u>...</u> 包裹,同时去掉 text-decoration: underline;
    • font-weight: normal; -> 直接干掉该样式
    • font-style: normal; -> 直接干掉该样式
    • text-decoration: none; -> 直接干掉该样式
  • 样式类

    • color: #333; -> 此标签内部内容用 <font color="#333">...</font> 包裹,同时去掉 color: #333;
    • font-size: 24px; -> 此标签内部内容用 <font size="5">...</font> 包裹,同时去掉 font-size: 24px;
    • 以上两种都存在,在只需要 1个 <font>...</font> 即可

    最后,去掉 含有 style="" 的标签

  • font-size 转化规则

    • 32px -> 6
    • 24px -> 5
    • 18px -> 4
    • 16px -> 3
    • 13px -> 2
    • 12px -> 1

before:

<p style="font-weight: bold; font-style: italic; text-decoration: underline;">
    <a href="https://www.kaola.com" 
       target="_blank" 
       style="font-size: 24px; color: #333">
        这是一段文本
    </a>
</p>
<p style="font-weight: bold;">
    <img src="https://i.loli.net/2017/12/28/5a44ef4cb0672.jpg">
</p>
<ul>
    <li>first</li>
    <li>second</li>
    <li>third</li>
</ul>

after:

<p>
    <b>
        <i>
            <u>
                <a href="https://www.kaola.com" target="_blank">
                    <font size="5" color="#333">
                    这是一段文本
                    </font>
                </a>
            </u>
        </i>
    </b>
</p>
<p>
    <b>
        <img src="https://i.loli.net/2017/12/28/5a44ef4cb0672.jpg">
    </b>
</p>
<ul>
    <li>first</li>
    <li>second</li>
    <li>third</li>
</ul>

 

二、思路

字符串替换。

1.先找到带style属性的标签,然后按规则替换成标签;如果颜色用rgb表示的,要转成十六进制;

2.用Jsoup解析一遍,填补结束标签;

3.Jsoup解析,删除所有style属性

三、代码

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HtmlStyleParser {
    private HtmlStyleParser(){
    }

    private volatile static HtmlStyleParser instance;

    public static HtmlStyleParser getInstance(){
        if (instance == null) {
            synchronized (HtmlStyleParser.class) {
                if (instance == null) {
                    instance = new HtmlStyleParser();
                }
            }
        }

        return instance;
    }

    public String parse(String html) {
        //把style属性转成标签
        String htmlStyle2Tag = style2Tag(html);
        if (StringUtils.isBlank(htmlStyle2Tag)){
            return null;
        }

        //用Jsoup解析,填补结束标签
        Document document = Jsoup.parse(htmlStyle2Tag, "", Parser.xmlParser());
        Elements elements = document.select("[style]");
        if (CollectionUtils.isEmpty(elements)) {
            return htmlStyle2Tag;
        }

        for (Element element : elements) {
            element.removeAttr("style");
        }

        return document.toString();
    }


    /**
     * 解析CSS style属性,转成标签
     * @param html
     * @return
     */
    public String style2Tag(String html) {
        //取出style属性
        String regex = "<(\\s*?(\\w+)[\\s\\S]*?(style[\\s\\S]*?=\"([\\s\\S]*?)\"[\\s\\S]*?))>";

        Pattern p = Pattern.compile(regex, Pattern.MULTILINE);
        Matcher m = p.matcher(html);

        String newHtml = html;
        Set<String> findedTags = new HashSet<>(); //匹配到之后将匹配到的字符串放进来,防止重复匹配

        while (m.find()) {
            //<p style="font-weight: bold; font-style: italic; text-decoration: underline;">
            String tagAndStyle = m.group();
            if (StringUtils.isBlank(tagAndStyle) || findedTags.contains(tagAndStyle)) {
                continue;
            }
            String styleVal = m.group(4).trim();

            if (StringUtils.isBlank(styleVal)) {
                continue;
            }

            //font-weight: bold; font-style: normal;
            String[] styleArray = styleVal.split(";");
            if (ArrayUtils.isEmpty(styleArray)) {
                continue;
            }

            Set<String> tagSet = new TreeSet<>(); //存<b>、<i>、<u>等标签名
            Set<String> fontSet = new TreeSet<>(); //存font-size、color

            //style转成tag
            this.convertTagAndFont(styleArray, tagSet, fontSet);

            String tagStr = null;
            if (CollectionUtils.isNotEmpty(tagSet)) {
                tagStr = StringUtils.join(tagSet.toArray());
            }

            String fontStr = null;
            if (CollectionUtils.isNotEmpty(fontSet)) {
                fontStr = "<font " + StringUtils.join(fontSet.toArray(), " ") + ">";
            }

            StringBuilder newTagProperties = new StringBuilder(tagAndStyle);
            if (StringUtils.isNotBlank(tagStr)) {
                newTagProperties.append(tagStr);
            }
            if (StringUtils.isNotBlank(fontStr)) {
                newTagProperties.append(fontStr);
            }

            newHtml = newHtml.replace(tagAndStyle, newTagProperties.toString());
            findedTags.add(tagAndStyle);
        }

        return newHtml;
    }

    /**
     * 把css的style属性解析成tag
     * @param styleArray
     * @param tagSet
     * @param fontSet
     */
    private void convertTagAndFont(String[] styleArray, Set<String> tagSet, Set<String> fontSet) {
        if (ArrayUtils.isEmpty(styleArray) || tagSet == null || fontSet == null) {
            return;
        }

        for (String styleStr : styleArray) {
            if (StringUtils.isBlank(styleStr) || !styleStr.contains(":")) {
                continue;
            }

            String[] styleKeyVal = styleStr.split(":");
            if (ArrayUtils.isEmpty(styleKeyVal) || styleKeyVal.length < 2) {
                continue;
            }

            if (StringUtils.isBlank(styleKeyVal[0]) || StringUtils.isBlank(styleKeyVal[1])) {
                continue;
            }

            String styleKey = styleKeyVal[0].trim();
            String styleVal = styleKeyVal[1].trim();

            if ("font-weight".equalsIgnoreCase(styleKey) && "bold".equalsIgnoreCase(styleVal)) {
                tagSet.add("<b>");
            } else if ("font-style".equalsIgnoreCase(styleKey) && "italic".equalsIgnoreCase(styleVal)) {
                tagSet.add("<i>");
            } else if ("text-decoration".equalsIgnoreCase(styleKey) && "underline".equalsIgnoreCase(styleVal)) {
                tagSet.add("<u>");
            } else if ("font-size".equalsIgnoreCase(styleKey) && FONT_SIZE_MAP.containsKey(styleVal)) {
                fontSet.add("size=" + FONT_SIZE_MAP.get(styleVal));
            } else if ("color".equalsIgnoreCase(styleKey)) {
                fontSet.add(styleKey + "=" + rgb2HexIfExists(styleVal));
            }
        }
    }

    /**
     * rgb格式的颜色转成十六进制。如果不是rgb,则返回原样。
     * @param rgb
     * @return
     */
    private String rgb2HexIfExists(String rgb) {
        if (StringUtils.isBlank(rgb)) {
            return null;
        }

        String rgbRegex = "rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)";
        Pattern p = Pattern.compile(rgbRegex);
        Matcher m1 = p.matcher(rgb);

        try {
            while (m1.find()) {
                String r = m1.group(1);
                String g = m1.group(2);
                String b = m1.group(3);
                rgb = String.format("#%02x%02x%02x", Integer.valueOf(r), Integer.valueOf(g), Integer.valueOf(b));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return rgb;
    }

    //字体大小映射
    private static final Map<String, Integer> FONT_SIZE_MAP = new HashMap<String, Integer>(6){{
        put("32px", 6);
        put("24px", 5);
        put("18px", 4);
        put("16px", 3);
        put("13px", 2);
        put("12px", 1);
    }};
}

猜你喜欢

转载自blog.csdn.net/u010266988/article/details/81539736
今日推荐