001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.search.highlight;
016    
017    import com.liferay.portal.kernel.search.Document;
018    import com.liferay.portal.kernel.search.Field;
019    import com.liferay.portal.kernel.util.ArrayUtil;
020    import com.liferay.portal.kernel.util.StringBundler;
021    import com.liferay.portal.kernel.util.StringPool;
022    import com.liferay.portal.kernel.util.StringUtil;
023    import com.liferay.portal.kernel.util.Validator;
024    
025    import java.util.Set;
026    import java.util.StringTokenizer;
027    import java.util.regex.Matcher;
028    import java.util.regex.Pattern;
029    
030    /**
031     * @author Tibor Lipusz
032     */
033    public class HighlightUtil {
034    
035            public static final String HIGHLIGHT_TAG_CLOSE = "</liferay-hl>";
036    
037            public static final String HIGHLIGHT_TAG_OPEN = "<liferay-hl>";
038    
039            public static final String[] HIGHLIGHTS =
040                    {"<span class=\"highlight\">", "</span>"};
041    
042            public static void addSnippet(
043                    Document document, Set<String> queryTerms, String snippet,
044                    String snippetFieldName) {
045    
046                    if (!snippet.equals(StringPool.BLANK)) {
047                            Matcher matcher = _pattern.matcher(snippet);
048    
049                            while (matcher.find()) {
050                                    queryTerms.add(matcher.group(1));
051                            }
052    
053                            snippet = StringUtil.replace(
054                                    snippet, HIGHLIGHT_TAG_OPEN, StringPool.BLANK);
055                            snippet = StringUtil.replace(
056                                    snippet, HIGHLIGHT_TAG_CLOSE, StringPool.BLANK);
057                    }
058    
059                    document.addText(
060                            Field.SNIPPET.concat(StringPool.UNDERLINE).concat(snippetFieldName),
061                            snippet);
062            }
063    
064            public static String highlight(String s, String[] queryTerms) {
065                    return highlight(s, queryTerms, HIGHLIGHTS[0], HIGHLIGHTS[1]);
066            }
067    
068            public static String highlight(
069                    String s, String[] queryTerms, String highlight1, String highlight2) {
070    
071                    if (Validator.isNull(s) || ArrayUtil.isEmpty(queryTerms)) {
072                            return s;
073                    }
074    
075                    if (queryTerms.length == 0) {
076                            return StringPool.BLANK;
077                    }
078    
079                    StringBundler sb = new StringBundler(2 * queryTerms.length - 1);
080    
081                    for (int i = 0; i < queryTerms.length; i++) {
082                            sb.append(Pattern.quote(queryTerms[i].trim()));
083    
084                            if ((i + 1) < queryTerms.length) {
085                                    sb.append(StringPool.PIPE);
086                            }
087                    }
088    
089                    int flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
090    
091                    Pattern pattern = Pattern.compile(sb.toString(), flags);
092    
093                    return _highlight(s, pattern, highlight1, highlight2);
094            }
095    
096            private static String _highlight(
097                    String s, Pattern pattern, String highlight1, String highlight2) {
098    
099                    StringTokenizer st = new StringTokenizer(s);
100    
101                    if (st.countTokens() == 0) {
102                            return StringPool.BLANK;
103                    }
104    
105                    StringBundler sb = new StringBundler(2 * st.countTokens() - 1);
106    
107                    while (st.hasMoreTokens()) {
108                            String token = st.nextToken();
109    
110                            Matcher matcher = pattern.matcher(token);
111    
112                            if (matcher.find()) {
113                                    StringBuffer hightlighted = new StringBuffer();
114    
115                                    while (true) {
116                                            matcher.appendReplacement(
117                                                    hightlighted,
118                                                    highlight1 + matcher.group() + highlight2);
119    
120                                            if (!matcher.find()) {
121                                                    break;
122                                            }
123                                    }
124    
125                                    matcher.appendTail(hightlighted);
126    
127                                    sb.append(hightlighted);
128                            }
129                            else {
130                                    sb.append(token);
131                            }
132    
133                            if (st.hasMoreTokens()) {
134                                    sb.append(StringPool.SPACE);
135                            }
136                    }
137    
138                    return sb.toString();
139            }
140    
141            private static final Pattern _pattern = Pattern.compile(
142                    HIGHLIGHT_TAG_OPEN + "(.*?)" + HIGHLIGHT_TAG_CLOSE);
143    
144    }