Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Citation key, make it possible for an empty field to fall back to a custom field #7111

Closed
lantyn opened this issue Nov 21, 2020 · 7 comments · Fixed by #7734
Closed

Citation key, make it possible for an empty field to fall back to a custom field #7111

lantyn opened this issue Nov 21, 2020 · 7 comments · Fixed by #7734

Comments

@lantyn
Copy link

lantyn commented Nov 21, 2020

Nowadays, most articles from online database already have their unique identifiers.
I personally prefer to use [authorsAlpha][eprint] as the default pattern for citation key.
It expands the default [author][year] pattern (the information of [year] is already contained in [eprint]); moreover, it automatically avoid duplicate keys.
However, it is not compatible with old articles with no [eprint] field. So I hope that when [eprint] is empty, it automatically falls back to [year]. Currently JabRef has the feature to replace an empty field with a custom string, which is actually not informative at all and thus not practical. Also when [author] is empty then [editor] is automatically used. So why not make this available to all empty fields with customizable fallback field? The syntax may be simply [eprint:[year]].

@Siedlerchr
Copy link
Member

This should be possible at least to define a fallback
https://docs.jabref.org/setup/citationkeypatterns#citation-key-patterns

:(x): The string between the parentheses will be inserted if the field marker preceding this modifier resolves to an empty value. The placeholder x may be any string. For instance, the marker [VOLUME:(unknown)] will return the entry's volume if set, and the string unknown if the entry's VOLUME field is not set

@k3KAW8Pnf7mkmdSMPHz27 Do you know if it's possible to define a fallback field?

@k3KAW8Pnf7mkmdSMPHz27
Copy link
Member

Nowadays, most articles from online database already have their unique identifiers.

You are referring to eprint?

Currently JabRef has the feature to replace an empty field with a custom string,

It would be better if it supported fields/bracketed expressions as well, yup.

You might be able to workaround the issue using the replace regular expression feature with an empty string. I am not familiar enough with regex and the year/eprint fields to come up with something good, but for the pattern [author]|[eprint][year] something along the lines of (?<=|)\d\d\d\d$ (replace the last 4 digits if they are not preceded by |) might work (even if it doesn't give the exact results that you want)?

So why not make this available to all empty fields with customizable fallback field?

I like the idea ``

The syntax may be simply [eprint:[year]]

I'd recommend [eprint:([year])], in that case, for consistency. I'd be happy to review/help out if you are interested in implementing this.

} else if (!modifier.isEmpty() && (modifier.length() >= 2) && (modifier.charAt(0) == '(') && modifier.endsWith(")")) {
// Alternate text modifier in parentheses. Should be inserted if the label is empty
if (label.isEmpty() && (modifier.length() > 2)) {
resultingLabel = modifier.substring(1, modifier.length() - 1);
}

Is the (current) replacement modifier.

Do you know if it's possible to define a fallback field?

As far as I know, no =/

@lantyn
Copy link
Author

lantyn commented Nov 22, 2020

Nowadays, most articles from online database already have their unique identifiers.

Yes, eprint or even doi. I don't like the [year] field because new articles tend to have both a preprint and a reprint with different [year]. When I update the reprint info from a preprint, the year changes, which then messes up the bibtex key and the pdf file names. I then decided to use eprint instead of year which is unique and persistent.

I do have my personal workaround via regex.
I set the pattern [authorsAlpha]:[year]:[eprint], then replace :(.*):$|:.*:(\S) with $1$2.
So when [eprint] in not empty I get [authorsAlpha][eprint], otherwise I get [authorsAlpha][year].
Such hacking should work for customizing a fallback of any empty field.

However, I suppose that in the current version you can do regex replace only once. I would be already happy if it was allowed to add several regex replacement rules.

@k3KAW8Pnf7mkmdSMPHz27
Copy link
Member

Such hacking should work for customizing a fallback of any empty field.

Nice! Might be that others can use this meanwhile.

However, I suppose that in the current version you can do regex replace only once. I would be already happy if it was allowed to add several regex replacement rules.

Agreed.

@SuXiChangZhen
Copy link
Contributor

@k3KAW8Pnf7mkmdSMPHz27 Hi, I am interested in this issue. Where can I get started and What is the expected behavior of citation key generation? Thank you.

@k3KAW8Pnf7mkmdSMPHz27
Copy link
Member

k3KAW8Pnf7mkmdSMPHz27 commented May 11, 2021

Hello @SuXiChangZhen, thank you for your interest!

Pretty much all approaches start with the "alternative text modifier" as described above,

} else if (!modifier.isEmpty() && (modifier.length() >= 2) && (modifier.charAt(0) == '(') && modifier.endsWith(")")) {
// Alternate text modifier in parentheses. Should be inserted if the label is empty
if (label.isEmpty() && (modifier.length() > 2)) {
resultingLabel = modifier.substring(1, modifier.length() - 1);
}

It is listed as the last modifier in the JabRef documentation.

There isn't necessarily one "right" answer to this issue. The code is old and has a few violations against good coding principles making it harder to deal with it. Mostly I'd advise against trying to refactor the whole BracketedPattern class because it would be very time-consuming. I'd guest the best effort/utility trade-off would be to extend the method injection code found among other places in,

return expandBrackets(citationKeyPattern.get(0), expandBracketContent(entry));
}
/**
* A helper method to create a {@link Function} that takes a single bracketed expression, expands it, and cleans the key.
*
* @param entry the {@link BibEntry} that a citation key is generated for
* @return a cleaned citation key for the given {@link BibEntry}
*/
private Function<String, String> expandBracketContent(BibEntry entry) {
Character keywordDelimiter = citationKeyPatternPreferences.getKeywordDelimiter();
return (String bracket) -> {
String expandedPattern;
List<String> fieldParts = parseFieldAndModifiers(bracket);
expandedPattern = removeUnwantedCharacters(getFieldValue(entry, fieldParts.get(0), keywordDelimiter, database), unwantedCharacters);
// check whether there is a modifier on the end such as
// ":lower":
if (fieldParts.size() > 1) {
// apply modifiers:
expandedPattern = applyModifiers(expandedPattern, fieldParts, 1);
}
return cleanKey(expandedPattern, unwantedCharacters);
};
}

so that

static String applyModifiers(final String label, final List<String> parts, final int offset) {

can parse and expand whatever is between the parentheses, i.e., make the same type of call as in

return expandBrackets(citationKeyPattern.get(0), expandBracketContent(entry));

Does that sort of make sense?

You are also free to solve it in some completely different way.

expected behavior of citation key generation

I am not sure that I understand your question. The bracketed patterns were originally intended to create a citation key from bibentries by accessing its fields, (e.g., [TITLE] accesses StandardField.TITLE) with some special keywords creating shorter/easier-to-read citation keys (e.g. [title]). The issue here is regarding accessing a different field if [title] resolves into an empty string. At the moment it is only possible to use a string instead, e.g., [TITLE:(NoTitle)], to generate the citation key "NoTitle" if the bibentry has no title. But it would be good to be able to replace it with a different field instead (e.g., [EPRINT:([YEAR])], if there is no EPRINT field, try to use the YEAR field instead),

@SuXiChangZhen
Copy link
Contributor

Thank you for your advice. I think I understand the need. I will make a pr soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

4 participants