Skip to content

Commit

Permalink
Bring back authorsAlpha citation key pattern (#12499)
Browse files Browse the repository at this point in the history
* Bring back original `authorsAlpha`

Signed-off-by: subhramit <subhramit.bb@live.in>

* Rename "V2" to "LNI"

Signed-off-by: subhramit <subhramit.bb@live.in>

* Add changelog entries

Signed-off-by: subhramit <subhramit.bb@live.in>

* Refine changelog entry

Signed-off-by: subhramit <subhramit.bb@live.in>

* Fix citation key generator tests

Signed-off-by: subhramit <subhramit.bb@live.in>

* Better lint in`BracketedPatternTest`

Signed-off-by: subhramit <subhramit.bb@live.in>

---------

Signed-off-by: subhramit <subhramit.bb@live.in>
  • Loading branch information
subhramit authored Feb 15, 2025
1 parent 19df622 commit 74d85d3
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- We improved the user comments field visibility so that it remains displayed if it contains text. Additionally, users can now easily toggle the field on or off via buttons unless disabled in preferences. [#11021](https://github.com/JabRef/jabref/issues/11021)
- The LibreOffice integration for CSL styles is now more performant. [#12472](https://github.com/JabRef/jabref/pull/12472)
- The "automatically sync bibliography when citing" feature of the LibreOffice integration is now disabled by default (can be enabled in settings). [#12472](https://github.com/JabRef/jabref/pull/12472)
- For the Citation key generator patterns, we reverted how `[authorsAlpha]` would behave to the original pattern and renamed the LNI-based pattern introduced in V6.0-alpha to `[authorsAlphaLNI]`. [#12499](https://github.com/JabRef/jabref/pull/12499)

### Fixed

Expand All @@ -39,6 +40,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- We fixed an issue where mixing JStyle and CSL style citations in LibreOffice caused two separate bibliography sections to be generated. [#12262](https://github.com/JabRef/jabref/issues/12262)
- We fixed an issue in the LibreOffice integration where the formatting of text (e.g. superscript) was lost when using certain numeric CSL styles. [melting-pot#772](https://github.com/JabRef/jabref-issue-melting-pot/issues/772)
- We fixed an issue where CSL style citations with citation keys having special characters (such as hyphens or colons) would not be recognized as valid by JabRef. [forum#5431](https://discourse.jabref.org/t/error-when-connecting-to-libreoffice/5431)
- We fixed an issue where the `[authorsAlpha]` pattern in Citation key generator would not behave as per the user documentation. [#12312](https://github.com/JabRef/jabref/issues/12312)

### Removed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ public static String getFieldValue(BibEntry entry, String pattern, Character key
return allAuthors(authorList);
case "authorsAlpha":
return authorsAlpha(authorList);
case "authorsAlphaLNI":
return authorsAlphaLNI(authorList);
case "authorLast":
return lastAuthor(authorList);
case "authorLastForeIni":
Expand Down Expand Up @@ -849,6 +851,61 @@ static String allAuthors(AuthorList authorList) {
* @return the initials of all authors' names
*/
public static String authorsAlpha(AuthorList authorList) {
StringBuilder alphaStyle = new StringBuilder();
int maxAuthors;
final boolean maxAuthorsExceeded;
if (authorList.getNumberOfAuthors() <= MAX_ALPHA_AUTHORS) {
maxAuthors = authorList.getNumberOfAuthors();
maxAuthorsExceeded = false;
} else {
maxAuthors = MAX_ALPHA_AUTHORS - 1;
maxAuthorsExceeded = true;
}

if (authorList.getNumberOfAuthors() == 1) {
String[] firstAuthor = authorList.getAuthor(0).getNamePrefixAndFamilyName()
.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++) {
alphaStyle.append(firstAuthor[j], 0, 1);
}
// append last part of last name completely
alphaStyle.append(firstAuthor[firstAuthor.length - 1], 0,
Math.min(3, firstAuthor[firstAuthor.length - 1].length()));
} else {
boolean andOthersPresent = authorList.getAuthor(maxAuthors - 1).equals(Author.OTHERS);
if (andOthersPresent) {
maxAuthors--;
}
List<String> vonAndLastNames = authorList.getAuthors().stream()
.limit(maxAuthors)
.map(Author::getNamePrefixAndFamilyName)
.toList();
for (String vonAndLast : vonAndLastNames) {
// replace all whitespaces by " "
// split the lastname at " "
String[] nameParts = vonAndLast.replaceAll("\\s+", " ").trim().split(" ");
for (String part : nameParts) {
// use first character of each part of lastname
alphaStyle.append(part, 0, 1);
}
}
if (andOthersPresent || maxAuthorsExceeded) {
alphaStyle.append("+");
}
}
return alphaStyle.toString();
}

/**
* Returns the authors according to the <a href="https://github.com/michel-kraemer/citeproc-java">BibTeX LNI template</a>
* Examples: <a href="https://github.com/gi-ev/biblatex-lni/blob/main/basic-test-en.tex">Examples from the tmplate</a>
* Also see discussion at the <a href="https://github.com/JabRef/jabref/pull/11614">pull request that introduced this</a>.
*
* @param authorList an {@link AuthorList}
* @return the initials of all authors' names
*/
public static String authorsAlphaLNI(AuthorList authorList) {
StringBuilder alphaStyle = new StringBuilder();
int numberOfAuthors = authorList.getNumberOfAuthors();
boolean andOthersPresent = numberOfAuthors > 1 &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public static String generateAlphanumericCitation(List<BibEntry> entries, BibDat

if (author.isPresent() && year.isPresent()) {
AuthorList authorList = AuthorList.parse(author.get());
String alphaKey = BracketedPattern.authorsAlpha(authorList);
String alphaKey = BracketedPattern.authorsAlphaLNI(authorList);

// Extract last two digits of the year
String shortYear = year.get().length() >= 2 ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ static Stream<Arguments> allAuthors() {
Arguments.of("AachenBerlinChemnitzDüsseldorf", "Aachen and Berlin and Chemnitz and Düsseldorf"),
Arguments.of("AachenBerlinChemnitzDüsseldorfEtAl", "Aachen and Berlin and Chemnitz and Düsseldorf and others"),
Arguments.of("AachenBerlinChemnitzDüsseldorfEssen", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen"),
Arguments.of("AachenBerlinChemnitzDüsseldorfEssenEtAl", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others"));
Arguments.of("AachenBerlinChemnitzDüsseldorfEssenEtAl", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others")
);
}

@ParameterizedTest
Expand All @@ -78,6 +79,25 @@ void allAuthors(String expected, AuthorList list) {
}

static Stream<Arguments> authorsAlpha() {
return Stream.of(
Arguments.of("A+", "Alexander Artemenko and others"),
Arguments.of("A+", "Aachen and others"),
Arguments.of("AB+", "Aachen and Berlin and others"),
Arguments.of("ABC+", "Aachen and Berlin and Chemnitz and others"),
Arguments.of("ABCD", "Aachen and Berlin and Chemnitz and Düsseldorf"),
Arguments.of("ABC+", "Aachen and Berlin and Chemnitz and Düsseldorf and others"),
Arguments.of("ABC+", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen"),
Arguments.of("ABC+", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others")
);
}

@ParameterizedTest
@MethodSource
void authorsAlpha(String expected, AuthorList list) {
assertEquals(expected, BracketedPattern.authorsAlpha(list));
}

static Stream<Arguments> authorsAlphaLNI() {
return Stream.of(
Arguments.of("Ar", "Alexander Artemenko and others"),
Arguments.of("Aa", "Aachen and others"),
Expand All @@ -104,8 +124,8 @@ static Stream<Arguments> authorsAlpha() {

@ParameterizedTest
@MethodSource
void authorsAlpha(String expected, AuthorList list) {
assertEquals(expected, BracketedPattern.authorsAlpha(list));
void authorsAlphaLNI(String expected, AuthorList list) {
assertEquals(expected, BracketedPattern.authorsAlphaLNI(list));
}

/**
Expand All @@ -128,7 +148,8 @@ static Stream<Arguments> oneAuthorPlusInitials() {
Arguments.of("AacheBCD", "Aachen and Berlin and Chemnitz and Düsseldorf"),
Arguments.of("AacheBCD+", "Aachen and Berlin and Chemnitz and Düsseldorf and others"),
Arguments.of("AacheBCDE", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen"),
Arguments.of("AacheBCDE+", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others"));
Arguments.of("AacheBCDE+", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others")
);
}

@ParameterizedTest
Expand All @@ -152,7 +173,8 @@ static Stream<Arguments> authShort() {
Arguments.of("ABC+", "Aachen and Berlin and Chemnitz and Düsseldorf"),
Arguments.of("ABC+", "Aachen and Berlin and Chemnitz and Düsseldorf and others"),
Arguments.of("ABC+", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen"),
Arguments.of("ABC+", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others"));
Arguments.of("ABC+", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others")
);
}

@ParameterizedTest
Expand All @@ -176,7 +198,8 @@ static Stream<Arguments> authIni1() {
Arguments.of("A", "Aachen and Berlin and Chemnitz and Düsseldorf"),
Arguments.of("A", "Aachen and Berlin and Chemnitz and Düsseldorf and others"),
Arguments.of("A", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen"),
Arguments.of("A", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others"));
Arguments.of("A", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others")
);
}

@ParameterizedTest
Expand All @@ -201,7 +224,8 @@ static Stream<Arguments> authIni2() {
Arguments.of("AB", "Aachen and Berlin and Chemnitz and Düsseldorf"),
Arguments.of("AB", "Aachen and Berlin and Chemnitz and Düsseldorf and others"),
Arguments.of("AB", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen"),
Arguments.of("AB", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others"));
Arguments.of("AB", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others")
);
}

@ParameterizedTest
Expand All @@ -226,7 +250,8 @@ static Stream<Arguments> authIni3() {
Arguments.of("ABC", "Aachen and Berlin and Chemnitz and Düsseldorf"),
Arguments.of("ABC", "Aachen and Berlin and Chemnitz and Düsseldorf and others"),
Arguments.of("ABC", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen"),
Arguments.of("ABC", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others"));
Arguments.of("ABC", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others")
);
}

@ParameterizedTest
Expand All @@ -250,7 +275,8 @@ static Stream<Arguments> authIni4() {
Arguments.of("ABCD", "Aachen and Berlin and Chemnitz and Düsseldorf"),
Arguments.of("ABCD", "Aachen and Berlin and Chemnitz and Düsseldorf and others"),
Arguments.of("ABCD", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen"),
Arguments.of("ABCD", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others"));
Arguments.of("ABCD", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others")
);
}

@ParameterizedTest
Expand All @@ -274,7 +300,8 @@ static Stream<Arguments> authEtAlDotDotEal() {
Arguments.of("Aachen.etal", "Aachen and Berlin and Chemnitz and Düsseldorf"),
Arguments.of("Aachen.etal", "Aachen and Berlin and Chemnitz and Düsseldorf and others"),
Arguments.of("Aachen.etal", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen"),
Arguments.of("Aachen.etal", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others"));
Arguments.of("Aachen.etal", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others")
);
}

@ParameterizedTest
Expand All @@ -298,7 +325,8 @@ static Stream<Arguments> authAuthEa() {
Arguments.of("Aachen.Berlin.ea", "Aachen and Berlin and Chemnitz and Düsseldorf"),
Arguments.of("Aachen.Berlin.ea", "Aachen and Berlin and Chemnitz and Düsseldorf and others"),
Arguments.of("Aachen.Berlin.ea", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen"),
Arguments.of("Aachen.Berlin.ea", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others"));
Arguments.of("Aachen.Berlin.ea", "Aachen and Berlin and Chemnitz and Düsseldorf and Essen and others")
);
}

@ParameterizedTest
Expand All @@ -321,7 +349,8 @@ void authShort(String expected, AuthorList list) {
"'New', '[auth3]', 'Isaac Newton'",
"'New', '[auth3_1]', 'Isaac Newton'",
"'Newton', '[authshort]', 'Isaac Newton'",
"'Ne', '[authorsAlpha]', 'Isaac Newton'",
"'New', '[authorsAlpha]', 'Isaac Newton'",
"'Ne', '[authorsAlphaLNI]', 'Isaac Newton'",
"'Newton', '[authorLast]', 'Isaac Newton'",
"'I', '[authorLastForeIni]', 'Isaac Newton'",

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class CitationKeyGeneratorTest {
private static final String AUTHFOREINI = "[authForeIni]";
private static final String AUTHFIRSTFULL = "[authFirstFull]";
private static final String AUTHORSALPHA = "[authorsAlpha]";
private static final String AUTHORSALPHALNI = "[authorsAlphaLNI]";
private static final String AUTHORLAST = "[authorLast]";
private static final String AUTHORLASTFOREINI = "[authorLastForeIni]";
private static final String AUTHORINI = "[authorIni]";
Expand Down Expand Up @@ -510,14 +511,33 @@ static Stream<Arguments> authors() {

static Stream<Arguments> authorsAlpha() {
return Stream.of(
Arguments.of("Ne", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_1, AUTHORSALPHA),
Arguments.of("New", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_1, AUTHORSALPHA),
Arguments.of("NM", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_2, AUTHORSALPHA),
Arguments.of("NME", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_3, AUTHORSALPHA),
Arguments.of("NMEB", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_4, AUTHORSALPHA),
Arguments.of("NMEB", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_5, AUTHORSALPHA),
Arguments.of("Aa", AUTHOR_FIRSTNAME_FULL_LASTNAME_FULL_WITH_VAN_COUNT_1, AUTHORSALPHA),
Arguments.of("AL", AUTHOR_FIRSTNAME_FULL_LASTNAME_FULL_WITH_VAN_COUNT_2, AUTHORSALPHA),
Arguments.of("Ne", AUTHOR_FIRSTNAME_FULL_LASTNAME_FULL_AND_OTHERS_COUNT_3, AUTHORSALPHA)
Arguments.of("NME+", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_5, AUTHORSALPHA),
Arguments.of("vdAal", AUTHOR_FIRSTNAME_FULL_LASTNAME_FULL_WITH_VAN_COUNT_1, AUTHORSALPHA),
Arguments.of("vdAvL", AUTHOR_FIRSTNAME_FULL_LASTNAME_FULL_WITH_VAN_COUNT_2, AUTHORSALPHA),
Arguments.of("NM+", AUTHOR_FIRSTNAME_FULL_LASTNAME_FULL_AND_OTHERS_COUNT_3, AUTHORSALPHA)
);
}

@ParameterizedTest
@MethodSource
void authorsAlphaLNI(String expected, BibEntry entry, String pattern) {
assertEquals(expected, generateKey(entry, pattern));
}

static Stream<Arguments> authorsAlphaLNI() {
return Stream.of(
Arguments.of("Ne", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_1, AUTHORSALPHALNI),
Arguments.of("NM", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_2, AUTHORSALPHALNI),
Arguments.of("NME", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_3, AUTHORSALPHALNI),
Arguments.of("NMEB", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_4, AUTHORSALPHALNI),
Arguments.of("NMEB", AUTHOR_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_5, AUTHORSALPHALNI),
Arguments.of("Aa", AUTHOR_FIRSTNAME_FULL_LASTNAME_FULL_WITH_VAN_COUNT_1, AUTHORSALPHALNI),
Arguments.of("AL", AUTHOR_FIRSTNAME_FULL_LASTNAME_FULL_WITH_VAN_COUNT_2, AUTHORSALPHALNI),
Arguments.of("Ne", AUTHOR_FIRSTNAME_FULL_LASTNAME_FULL_AND_OTHERS_COUNT_3, AUTHORSALPHALNI)
);
}

Expand Down

0 comments on commit 74d85d3

Please sign in to comment.