Package net.sf.jabref.labelPattern

Source Code of net.sf.jabref.labelPattern.LabelPatternUtil

/*
* Created on 13-Dec-2003
*/
package net.sf.jabref.labelPattern;

import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.Arrays;
import java.util.List;

import net.sf.jabref.*;
import net.sf.jabref.export.layout.format.RemoveLatexCommands;

/**
*
* @author Ulrik Stervbo (ulriks AT ruc.dk)
*/
/**
* This is the utility class of the LabelPattern package.
* @author Ulrik Stervbo (ulriks AT ruc.dk)
*/
public class LabelPatternUtil {

    // All single characters that we can use for extending a key to make it unique:
    private static String CHARS = "abcdefghijklmnopqrstuvwxyz";

    public static ArrayList<String> DEFAULT_LABELPATTERN;
    static {
        updateDefaultPattern();
    }

    private static BibtexDatabase _db;

    public static void updateDefaultPattern() {
        DEFAULT_LABELPATTERN = split(JabRefPreferences.getInstance().get("defaultLabelPattern"));
    }

    /**
     * This method takes a string of the form [field1]spacer[field2]spacer[field3]...,
     * where the fields are the (required) fields of a BibTex entry. The string is split
     * into fields and spacers by recognizing the [ and ].
     *
     * @param labelPattern a <code>String</code>
     * @return an <code>ArrayList</code> The first item of the list
     * is a string representation of the key pattern (the parameter),
     * the second item is the spacer character (a <code>String</code>).
     */
    public static ArrayList<String> split(String labelPattern) {
        // A holder for fields of the entry to be used for the key
        ArrayList<String> _alist = new ArrayList<String>();

        // Before we do anything, we add the parameter to the ArrayLIst
        _alist.add(labelPattern);

        //String[] ss = labelPattern.split("\\[|\\]");
        StringTokenizer tok = new StringTokenizer(labelPattern, "[]", true);
        while (tok.hasMoreTokens()) {
            _alist.add(tok.nextToken());
        }
        return _alist;

        /*
       // Regular expresion for identifying the fields
       Pattern pi = Pattern.compile("\\[\\w*\\]");
       // Regular expresion for identifying the spacer
       Pattern ps = Pattern.compile("\\].()*\\[");

       // The matcher for the field
       Matcher mi = pi.matcher(labelPattern);
       // The matcher for the spacer char
       Matcher ms = ps.matcher(labelPattern);

       // Before we do anything, we add the parameter to the ArrayLIst
       _alist.add(labelPattern);

       // If we can find the spacer character
       if(ms.find()){
     String t_spacer = ms.group();
      // Remove the `]' and `[' at the ends
      // We cant imagine a spacer of omre than one character.
      t_spacer = t_spacer.substring(1,2);
      _alist.add(t_spacer);
       }

       while(mi.find()){
     // Get the matched string
     String t_str = mi.group();
      int _sindex = 1;
      int _eindex = t_str.length() -1;
      // Remove the `[' and `]' at the ends
      t_str = t_str.substring(_sindex, _eindex);
     _alist.add(t_str);
       }

       return _alist;*/
    }

    /**
     * Generates a BibTeX label according to the pattern for a given entry type, and
     * returns the <code>Bibtexentry</code> with the unique label.
     * @param table a <code>LabelPattern</code>
     * @param database a <code>BibtexDatabase</code>
     * @param _entry a <code>BibtexEntry</code>
     * @return modified Bibtexentry
     */
    public static BibtexEntry makeLabel(LabelPattern table,
        BibtexDatabase database, BibtexEntry _entry) {
        _db = database;
        ArrayList<String> _al;
        String _label;
        StringBuffer _sb = new StringBuffer();
        boolean forceUpper = false, forceLower = false;

        try {
            // get the type of entry
            String _type = _entry.getType().getName().toLowerCase();
            // Get the arrayList corrosponding to the type
            _al = table.getValue(_type);
            int _alSize = _al.size();
            boolean field = false;
            for (int i = 1; i < _alSize; i++) {
                String val = _al.get(i).toString();
                if (val.equals("[")) {
                    field = true;
                } else if (val.equals("]")) {
                    field = false;
                } else if (field) {
                    /*
                     * Edited by Seb Wills <saw27@mrao.cam.ac.uk> on 13-Apr-2004
                     * Added new pseudo-fields "shortyear" and "veryshorttitle",
                     * and and ":lower" modifier for all fields (in a way easily
                     * extended to other modifiers). Helpfile
                     * help/LabelPatterns.html updated accordingly.
                     */
                    // check whether there is a modifier on the end such as
                    // ":lower"
                    // String modifier = null;
                    String[] parts = parseFieldMarker(val);//val.split(":");

                    String label = makeLabel(_entry, parts[0]);
                   
                    // apply modifier if present
                    if (parts.length > 1)
                        label = applyModifiers(label, parts, 1);
                   
                    _sb.append(label);

                } else {
                    _sb.append(val);
                }
            }
        } catch (Exception e) {
            System.err.println(e);
        }


        // Remove all illegal characters from the key.
        _label = Util.checkLegalKey(_sb.toString());

        // Patch by Toralf Senger:
        // Remove Regular Expressions while generating Keys
        String regex = Globals.prefs.get("KeyPatternRegex");
        if ((regex != null) && (regex.trim().length() > 0)) {
            String replacement = Globals.prefs.get("KeyPatternReplacement");
            _label = _label.replaceAll(regex, replacement);
        }

        if (forceUpper) {
            _label = _label.toUpperCase();
        }
        if (forceLower) {
            _label = _label.toLowerCase();
        }

        String oldKey = _entry.getCiteKey();
        int occurences = _db.getNumberOfKeyOccurences(_label);

        if ((oldKey != null) && oldKey.equals(_label))
            occurences--; // No change, so we can accept one dupe.

        if (occurences == 0) {
            // No dupes found, so we can just go ahead.
            if (!_label.equals(oldKey))
                _db.setCiteKeyForEntry(_entry.getId(), _label);

        } else {
            // The key is already in use, so we must modify it.
            int number = 0;

            String moddedKey = _label + getAddition(number);
            occurences = _db.getNumberOfKeyOccurences(moddedKey);

            if ((oldKey != null) && oldKey.equals(moddedKey))
                occurences--;

            while (occurences > 0) {
                number++;
                moddedKey = _label + getAddition(number);

                occurences = _db.getNumberOfKeyOccurences(moddedKey);
                if ((oldKey != null) && oldKey.equals(moddedKey))
                    occurences--;
            }

            if (!moddedKey.equals(oldKey)) {
                _db.setCiteKeyForEntry(_entry.getId(), moddedKey);
            }
        }

        return _entry;
        /** End of edit, Morten Alver 2004.02.04.  */
    }

    /**
     * Applies modifiers to a label generated based on a field marker.
     * @param label The generated label.
     * @param parts String array containing the modifiers.
     * @param offset The number of initial items in the modifiers array to skip.
     * @return The modified label.
     */
    public static String applyModifiers(String label, String[] parts, int offset) {
        if (parts.length > offset)
            for (int j = offset; j < parts.length; j++) {
                String modifier = parts[j];

                if (modifier.equals("lower")) {
                    label = label.toLowerCase();
                } else if (modifier.equals("upper")) {
                    label = label.toUpperCase();
                } else if (modifier.equals("abbr")) {
                    // Abbreviate - that is,
                    // System.out.println(_sbvalue.toString());
                    StringBuffer abbr = new StringBuffer();
                    String[] words = label.toString().replaceAll("[\\{\\}']","")
                            .split("[ \r\n\"]");
                    for (int word = 0; word < words.length; word++)
                        if (words[word].length() > 0)
                            abbr.append(words[word].charAt(0));
                    label = abbr.toString();

                } else if (modifier.startsWith("(") && modifier.endsWith(")")) {
                    // Alternate text modifier in parentheses. Should be inserted if
                    // the label is empty:
                    if (label.equals("") && (modifier.length() > 2))
                        return modifier.substring(1, modifier.length()-1);

                } else {
                    Globals
                        .logger("Key generator warning: unknown modifier '"
                            + modifier + "'.");
                }
            }
        return label;
    }

    public static String makeLabel(BibtexEntry _entry, String val) {

        try {
            if (val.startsWith("auth") || val.startsWith("pureauth")) {

                /*
                 * For label code "auth...": if there is no author, but there
                 * are editor(s) (e.g. for an Edited Book), use the editor(s)
                 * instead. (saw27@mrao.cam.ac.uk). This is what most people
                 * want, but in case somebody really needs a field which expands
                 * to nothing if there is no author (e.g. someone who uses both
                 * "auth" and "ed" in the same label), we provide an alternative
                 * form "pureauth..." which does not do this fallback
                 * substitution of editor.
                 */
                String authString = _entry.getField("author");

                if (val.startsWith("pure")) {
                    // remove the "pure" prefix so the remaining
                    // code in this section functions correctly
                    val = val.substring(4);
                } else {
                    if (authString == null || authString.equals("")) {
                        authString = _entry.getField("editor");
                    }
                }

                // Gather all author-related checks, so we don't
                // have to check all the time.
                if (val.equals("auth")) {
                    return firstAuthor(authString);
                } else if (val.equals("authors")) {
                    return allAuthors(authString);
                } else if (val.equals("authorsAlpha")) {
                  return authorsAlpha(authString);
                }
                // Last author's last name
                else if (val.equals("authorLast")) {
                    return lastAuthor(authString);
                } else if (val.equals("authorIni")) {
                    String s = oneAuthorPlusIni(authString);
                    return s == null ? "" : s;
                } else if (val.matches("authIni[\\d]+")) {
                    int num = Integer.parseInt(val.substring(7));
                    String s = authIniN(authString, num);
                    return s == null ? "" : s;
                } else if (val.equals("auth.auth.ea")) {
                    String s = authAuthEa(authString);
                    return s == null ? "" : s;
                } else if (val.equals("auth.etal")) {
                    String s = authEtal(authString);
                    return s == null ? "" : s;
                } else if (val.equals("authshort")) {
                    String s = authshort(authString);
                    return s == null ? "" : s;
                } else if (val.matches("auth[\\d]+_[\\d]+")) {
                    String[] nums = val.substring(4).split("_");
                    String s = authN_M(authString, Integer.parseInt(nums[0]),
                        Integer.parseInt(nums[1]) - 1);
                    return s == null ? "" : s;
                } else if (val.matches("auth\\d+")) {
                    // authN. First N chars of the first author's last
                    // name.

                    int num = Integer.parseInt(val.substring(4));
                    String fa = firstAuthor(authString);
                    if (fa == null)
                        return "";
                    if (num > fa.length())
                        num = fa.length();
                    return fa.substring(0, num);
                } else if (val.matches("authors\\d+")) {
                    String s = NAuthors(authString, Integer.parseInt(val
                        .substring(7)));
                    return s == null ? "" : s;
                } else {
                    // This "auth" business was a dead end, so just
                    // use it literally:
                    return getField(_entry, val);
                }
            } else if (val.startsWith("ed")) {
                // Gather all markers starting with "ed" here, so we
                // don't have to check all the time.
                if (val.equals("edtr")) {
                    return firstAuthor(_entry.getField("editor").toString());
                } else if (val.equals("editors")) {
                    return allAuthors(_entry.getField("editor").toString());
                // Last author's last name
                } else if (val.equals("editorLast")) {
                    return lastAuthor(_entry.getField("editor").toString());
                } else if (val.equals("editorIni")) {
                    String s = oneAuthorPlusIni(_entry.getField("editor")
                        .toString());
                    return s == null ? "" : s;
                } else if (val.matches("edtrIni[\\d]+")) {
                    int num = Integer.parseInt(val.substring(7));
                    String s = authIniN(_entry.getField("editor").toString(), num);
                    return s == null ? "" : s;
                } else if (val.matches("edtr[\\d]+_[\\d]+")) {
                    String[] nums = val.substring(4).split("_");
                    String s = authN_M(_entry.getField("editor").toString(),
                        Integer.parseInt(nums[0]),
                        Integer.parseInt(nums[1]) - 1);
                    return s == null ? "" : s;
                } else if (val.equals("edtr.edtr.ea")) {
                    String s = authAuthEa(_entry.getField("editor").toString());
                    return s == null ? "" : s;
                } else if (val.equals("edtrshort")) {
                    String s = authshort(_entry.getField("editor").toString());
                    return s == null ? "" : s;
                }
                // authN. First N chars of the first author's last
                // name.
                else if (val.matches("edtr\\d+")) {
                    int num = Integer.parseInt(val.substring(4));
                    String fa = firstAuthor(_entry.getField("editor")
                        .toString());
                    if (fa == null)
                        return "";
                    if (num > fa.length())
                        num = fa.length();
                    return fa.substring(0, num);
                } else {
                    // This "ed" business was a dead end, so just
                    // use it literally:
                    return getField(_entry, val);
                }
            } else if (val.equals("firstpage")) {
                return firstPage(_entry.getField("pages"));
            } else if (val.equals("lastpage")) {
                return lastPage(_entry.getField("pages"));
            } else if (val.equals("shorttitle")) {
                return getTitleWords(3, _entry);
            } else if (val.equals("shortyear")) {
                String ss = _entry.getField("year");
                if (ss.startsWith("in") || ss.startsWith("sub")) {
                    return "IP";
                } else if (ss.length() > 2) {
                    return ss.substring(ss.length() - 2);
                } else {
                    return ss;
                }
            } else if (val.equals("veryshorttitle")) {
                return getTitleWords(1, _entry);
            } else if (val.matches("keyword\\d+")) {
                StringBuilder sb = new StringBuilder();
                int num = Integer.parseInt(val.substring(7));
                String kw = getField(_entry, "keywords");
                if (kw != null) {
                    String[] keywords = kw.split("[,;]\\s*");
                    if ((num > 0) && (num < keywords.length))
                        sb.append(keywords[num - 1].trim());
                }
                return sb.toString();
            } else {
                // we havent seen any special demands
                return getField(_entry, val);
            }
        } catch (NullPointerException ex) {
            return "";
        }

    }

    /**
     * Look up a field of a BibtexEntry, returning its String value, or an
     * empty string if it isn't set.
     * @param entry The entry.
     * @param field The field to look up.
     * @return The field value.
     */
    private static String getField(BibtexEntry entry, String field) {
        Object o = entry.getField(field);
        return o != null ? (String)o : "";
    }

    /**
     * Computes an appendix to a BibTeX key that could make it unique. We use
     * a-z for numbers 0-25, and then aa-az, ba-bz, etc.
     *
     * @param number
     *            The appendix number.
     * @return The String to append.
     */
    private static String getAddition(int number) {
        if (number >= CHARS.length()) {
            int lastChar = number % CHARS.length();
            return getAddition(number/CHARS.length()-1) + CHARS.substring(lastChar, lastChar+1);
        } else
            return CHARS.substring(number, number+1);
    }


    static String getTitleWords(int number, BibtexEntry _entry) {
        String ss = (new RemoveLatexCommands()).format(_entry.getField("title").toString());
        StringBuffer _sbvalue = new StringBuffer(),
        current;
        int piv=0, words = 0;

        // sorry for being English-centric. I guess these
        // words should really be an editable preference.
        mainl: while ((piv < ss.length()) && (words < number)) {
            current = new StringBuffer();
            // Get the next word:
            while ((piv<ss.length()) && !Character.isWhitespace(ss.charAt(piv))) {
                current.append(ss.charAt(piv));
                piv++;
                //System.out.println(".. "+piv+" '"+current.toString()+"'");
            }
            piv++;
            // Check if it is ok:
            String word = current.toString().trim();
            if (word.length() == 0)
                continue mainl;
            for(int _i=0; _i< Globals.SKIP_WORDS.length; _i++) {
                if (word.equalsIgnoreCase(Globals.SKIP_WORDS[_i])) {
                    continue mainl;
                }
            }

            // If we get here, the word was accepted.
            if (_sbvalue.length() > 0)
                _sbvalue.append(" ");
            _sbvalue.append(word);
            words++;
        }

        return _sbvalue.toString();
    }


    /**
     * Tests whether a given label is unique.
     * @param label a <code>String</code>
     * @return <code>true</code> if and only if the <code>label</code> is unique
     */
    public static boolean isLabelUnique(String label) {
        boolean _isUnique = true;
        BibtexEntry _entry;
        int _dbSize = _db.getEntryCount();
        // run through the whole DB and check the key field
        // if this could be made recursive I would be very happy
        // it kinda sux that we have to run through the whole db.
        // The idea here is that if we meet NO match, the _duplicate
        // field will be true

        for (int i = 0; i < _dbSize; i++) {
            _entry = _db.getEntryById(String.valueOf(i));

            // oh my! there is a match! we better set the uniqueness to false
            // and leave this for-loop all together
            if (_entry.getField(BibtexFields.KEY_FIELD).equals(label)) {
                _isUnique = false;
                break;
            }
        }

        return _isUnique;

    }

    /**
     * Gets the last name of the first author/editor
     *
     * @param authorField
     *            a <code>String</code>
     * @return the surname of an author/editor or "" if no author was found
     *    This method is guaranteed to never return null.
     *
     * @throws NullPointerException
     *             if authorField == null
     */
    public static String firstAuthor(String authorField) {
        AuthorList al = AuthorList.getAuthorList(authorField);
        if (al.size() == 0)
            return "";
        String s = al.getAuthor(0).getLast();
        return s != null ? s : "";

    }

    /**
     * Gets the von part and the last name of the first author/editor
     *
     * @param authorField
     *            a <code>String</code>
     * @return the von part and surname of an author/editor or "" if no author was found.
     *  This method is guaranteed to never return null.
     *
     * @throws NullPointerException
     *             if authorField == null
     */
    public static String firstAuthorVonAndLast(String authorField) {
        AuthorList al = AuthorList.getAuthorList(authorField);
        if (al.size() == 0)
            return "";
        String s = al.getAuthor(0).getVon();
        StringBuilder sb = new StringBuilder();
        if (s != null) {
            sb.append(s);
            sb.append(' ');
        }
        s = al.getAuthor(0).getLast();
        if (s != null)
            sb.append(s);
        return sb.toString();
    }

    /**
     * Gets the last name of the last author/editor
     * @param authorField a <code>String</code>
     * @return the sur name of an author/editor
     */
    private static String lastAuthor(String authorField) {
        String[] tokens = AuthorList.fixAuthorForAlphabetization(authorField).split("\\band\\b");
        if (tokens.length > 0) { // if author is empty
            String[] lastAuthor = tokens[tokens.length-1].replaceAll("\\s+", " ").trim().split(" ");
            return lastAuthor[0];

        }
        else return "";
    }

    /**
     * Gets the last name of all authors/editors
     * @param authorField a <code>String</code>
     * @return the sur name of all authors/editors
     */
    private static String allAuthors(String authorField) {
        String author = "";
        // This code was part of 'ApplyRule' in 'ArticleLabelRule'
        String[] tokens = AuthorList.fixAuthorForAlphabetization(authorField).split("\\band\\b");
        int i = 0;
        while (tokens.length > i) {
            // convert lastname, firstname to firstname lastname
            String[] firstAuthor = tokens[i].replaceAll("\\s+", " ").trim().split(" ");
            // lastname, firstname
            author += firstAuthor[0];
            i++;
        }
        return author;
    }
   
    /**
     * Returns the authors according to the BibTeX-alpha-Style
     * @param authorField string containing the value of the author field
     * @return the initials of all authornames
     */
    private static String authorsAlpha(String authorField) {
      String authors = "";
     
      String fixedAuthors = AuthorList.fixAuthor_lastNameOnlyCommas(authorField, false);
     
      // drop the "and" before the last author
      // -> makes processing easier
      fixedAuthors = fixedAuthors.replace(" and ", ", ");
     
      String[] tokens = fixedAuthors.split(",");
      int max = (tokens.length > 4 ? 3 : tokens.length);
      if (max==1) {
      String[] firstAuthor = tokens[0].replaceAll("\\s+", " ").trim().split(" ");
      // take first letter of any "prefixes" (e.g. van der Aalst -> vd)
      for (int j=0; j<firstAuthor.length-1; j++) {
        authors = authors.concat(firstAuthor[j].substring(0,1));
      }
      // append last part of last name completely
      authors = authors.concat(firstAuthor[firstAuthor.length-1].substring(0,
                    Math.min(3, firstAuthor[firstAuthor.length-1].length())));
      } else {
        for (int i = 0; i < max; i++) {
          // replace all whitespaces by " "
          // split the lastname at " "
          String[] curAuthor = tokens[i].replaceAll("\\s+", " ").trim().split(" ");
          for (int j=0; j<curAuthor.length; j++) {
            // use first character of each part of lastname
            authors = authors.concat(curAuthor[j].substring(0, 1));
          }
        }
        if (tokens.length > 4) {
          authors = authors.concat("+");
        }
      }
      return authors;
    }

    /**
     * Gets the surnames of the first N authors and appends EtAl if there are more than N authors
     * @param authorField a <code>String</code>
     * @param n the number of desired authors
     * @return Gets the surnames of the first N authors and appends EtAl if there are more than N authors
     */
    private static String NAuthors(String authorField, int n) {
        String author = "";
        // This code was part of 'ApplyRule' in 'ArticleLabelRule'
        String[] tokens = AuthorList.fixAuthorForAlphabetization(authorField).split("\\band\\b");
        int i = 0;
        while (tokens.length > i && i < n) {
            // convert lastname, firstname to firstname lastname
            String[] firstAuthor = tokens[i].replaceAll("\\s+", " ").trim().split(" ");
            // lastname, firstname
            author += firstAuthor[0];
            i++;
        }
        if (tokens.length <= n) return author;
        return author += "EtAl";
    }

    /**
     * Gets the first part of the last name of the first
     * author/editor, and appends the last name initial of the
     * remaining authors/editors.
     * @param authorField a <code>String</code>
     * @return the sur name of all authors/editors
     */
    private static String oneAuthorPlusIni(String authorField) {
        final int CHARS_OF_FIRST = 5;
        authorField = AuthorList.fixAuthorForAlphabetization(authorField);
        String author = "";
        // This code was part of 'ApplyRule' in 'ArticleLabelRule'
        String[] tokens = authorField.split("\\band\\b");
        int i = 1;
        if (tokens.length == 0) {
            return author;
        }
        String[] firstAuthor = tokens[0].replaceAll("\\s+", " ").split(" ");
        author = firstAuthor[0].substring(0,
            Math.min(CHARS_OF_FIRST,
                firstAuthor[0].length()));
        while (tokens.length > i) {
            // convert lastname, firstname to firstname lastname
            author += tokens[i].trim().charAt(0);
            i++;
        }
        return author;

    }

    /**
     * auth.auth.ea format:
     * Isaac Newton and James Maxwell and Albert Einstein (1960)
     * Isaac Newton and James Maxwell (1960)
     *  give:
     * Newton.Maxwell.ea
     * Newton.Maxwell
     */
    private static String authAuthEa(String authorField) {
        authorField = AuthorList.fixAuthorForAlphabetization(authorField);
        StringBuffer author = new StringBuffer();

        String[] tokens = authorField.split("\\band\\b");
        if (tokens.length == 0) {
            return "";
        }
        author.append((tokens[0].split(","))[0]);
        if (tokens.length >= 2)
            author.append(".").append((tokens[1].split(","))[0]);
        if (tokens.length > 2)
            author.append(".ea");

        return author.toString();
    }

    /**
     * auth.etal format:
     * Isaac Newton and James Maxwell and Albert Einstein (1960)
     * Isaac Newton and James Maxwell (1960)
     *  give:
     * Newton.etal
     * Newton.Maxwell
     */
    private static String authEtal(String authorField) {
        authorField = AuthorList.fixAuthorForAlphabetization(authorField);
        StringBuffer author = new StringBuffer();

        String[] tokens = authorField.split("\\band\\b");
        if (tokens.length == 0) {
            return "";
        }
        author.append((tokens[0].split(","))[0]);
        if (tokens.length == 2)
            author.append(".").append((tokens[1].split(","))[0]);
        else if (tokens.length > 2)
            author.append(".etal");

        return author.toString();
    }

    /**
     * The first N characters of the Mth author/editor.
     */
    private static String authN_M(String authorField, int n, int m) {
        authorField = AuthorList.fixAuthorForAlphabetization(authorField);

        String[] tokens = authorField.split("\\band\\b");
        if ((tokens.length <= m) || (n<0) || (m<0)) {
            return "";
        }
        String lastName = (tokens[m].split(","))[0].trim();
        if (lastName.length() <= n)
            return lastName;
        else
            return lastName.substring(0, n);
    }

    /**
     * authshort format:
     * added by Kolja Brix, kbx@users.sourceforge.net
     *
     * given author names
     *
     *   Isaac Newton and James Maxwell and Albert Einstein and N. Bohr
     *
     *   Isaac Newton and James Maxwell and Albert Einstein
     *  
     *   Isaac Newton and James Maxwell
     *  
     *   Isaac Newton
     *
     * yield
     *
     *   NME+
     *  
     *   NME
     *  
     *   NM
     *  
     *   Newton
     */
    private static String authshort(String authorField) {
        authorField = AuthorList.fixAuthorForAlphabetization(authorField);
        StringBuffer author = new StringBuffer();
        String[] tokens = authorField.split("\\band\\b");
        int i = 0;

        if (tokens.length == 1) {

            author.append(authN_M(authorField,authorField.length(),0));

        } else if (tokens.length >= 2) {

            while (tokens.length > i && i<3) {
                author.append(authN_M(authorField,1,i));
                i++;
            }

            if (tokens.length > 3)
                author.append("+");

        }

        return author.toString();
    }

    /**
     * authIniN format:
     *
     * Each author gets (N div #authors) chars, the remaining (N mod #authors)
     * chars are equally distributed to the authors first in the row.
     *
     * If (N < #authors), only the first N authors get mentioned.
     *
     * For example if
     *
     * a) I. Newton and J. Maxwell and A. Einstein and N. Bohr (..)
     *
     * b) I. Newton and J. Maxwell and A. Einstein
     *
     * c) I. Newton and J. Maxwell
     *
     * d) I. Newton
     *
     * authIni4 gives: a) NMEB, b) NeME, c) NeMa, d) Newt
     *
     * @param authorField
     *            The authors to format.
     *
     * @param n
     *            The maximum number of characters this string will be long. A
     *            negative number or zero will lead to "" be returned.
     *
     * @throws NullPointerException
     *             if authorField is null and n > 0
     */
    public static String authIniN(String authorField, int n) {
       
        if (n <= 0)
            return "";
       
        authorField = AuthorList.fixAuthorForAlphabetization(authorField);
        StringBuffer author = new StringBuffer();
        String[] tokens = authorField.split("\\band\\b");
        int i = 0;
        int charsAll = n / tokens.length;

        if (tokens.length == 0) {
            return author.toString();
        }

        while (tokens.length > i) {
            if ( i < (n % tokens.length) ) {
                author.append(authN_M(authorField,charsAll+1,i));
            } else {
                author.append(authN_M(authorField,charsAll,i));
            }
            i++;
        }

        if (author.length() <= n)
            return author.toString();
        else
            return author.toString().substring(0, n);
    }


    /**
     * Split the pages field into separate numbers and return the lowest
     *
     * @param pages
     *            (may not be null) a pages string such as 42--111 or
     *            7,41,73--97 or 43+
     *
     * @return the first page number or "" if no number is found in the string
     *
     * @throws NullPointerException
     *             if pages is null
     */
    public static String firstPage(String pages) {
        String[] _pages = pages.split("\\D+");
        int result = Integer.MAX_VALUE;
        for (String n : _pages){
            if (n.matches("\\d+"))
                result = Math.min(Integer.parseInt(n), result);
        }
       
        if (result == Integer.MAX_VALUE)
            return "";
        else
            return String.valueOf(result);
    }

    /**
     * Split the pages field into separate numbers and return the highest
     *
     * @param pages
     *            a pages string such as 42--111 or 7,41,73--97 or 43+
     *
     * @return the first page number or "" if no number is found in the string
     *
     * @throws NullPointerException
     *             if pages is null.
     */
    public static String lastPage(String pages) {
        String[] _pages = pages.split("\\D+");
        int result = Integer.MIN_VALUE;
        for (String n : _pages){
            if (n.matches("\\d+"))
                result = Math.max(Integer.parseInt(n), result);
        }
       
        if (result == Integer.MIN_VALUE)
            return "";
        else
            return String.valueOf(result);
    }

    /**
         * Parse a field marker with modifiers, possibly containing a parenthesised modifier,
         * as well as escaped colons and parentheses.
         * @param arg The argument string.
         * @return An array of strings representing the parts of the marker
         */
        public static String[] parseFieldMarker(String arg) {
            List<String> parts = new ArrayList<String>();
            StringBuilder current = new StringBuilder();
            boolean escaped = false;
            int inParenthesis = 0;
            for (int i=0; i<arg.length(); i++) {
                if ((arg.charAt(i) == ':') && !escaped && (inParenthesis == 0)) {
                    parts.add(current.toString());
                    current = new StringBuilder();
                } else if ((arg.charAt(i) == '(') && !escaped) {
                    inParenthesis++;
                    current.append(arg.charAt(i));
                } else if ((arg.charAt(i) == ')') && !escaped && (inParenthesis > 0)) {
                    inParenthesis--;
                    current.append(arg.charAt(i));
                } else if (arg.charAt(i) == '\\') {
                    if (escaped) {
                        escaped = false;
                        current.append(arg.charAt(i));
                    } else
                        escaped = true;
                } else if (escaped) {
                    current.append(arg.charAt(i));
                    escaped = false;
                } else
                    current.append(arg.charAt(i));
            }
            parts.add(current.toString());
            return parts.toArray(new String[parts.size()]);
        }

}
TOP

Related Classes of net.sf.jabref.labelPattern.LabelPatternUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.