Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- We fixed an issue where the tab showing the fulltext search results would appear blank after switching library. [#13241](https://github.com/JabRef/jabref/issues/13241)
- We fixed an issue where the groups were still displayed after closing all libraries. [#13382](https://github.com/JabRef/jabref/issues/13382)
- Enhanced field selection logic in the Merge Entries dialog when fetching from DOI to prefer valid years and entry types. [#12549](https://github.com/JabRef/jabref/issues/12549)
- We fixed an issue where opening the ThreewayMerge dialog would throw an exception when one of the two year fields dos not contain a year. [#13673](https://github.com/JabRef/jabref/issues/13673)

### Removed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,23 @@ void newYearShouldBeSelectedForYearsWithLargeValueGap() {
}

@Test
void yearInRangeShouldBeSelected() {
void selectRightYearWhenInRange() {
BibEntry leftEntry = new BibEntry().withField(StandardField.YEAR, "1700");
BibEntry rightEntry = new BibEntry().withField(StandardField.YEAR, "2000");
FieldRowViewModel yearField = new FieldRowViewModel(StandardField.YEAR, leftEntry, rightEntry, mergedEntry, fieldMergerFactory);
yearField.autoSelectBetterValue();
assertEquals(FieldRowViewModel.Selection.RIGHT, yearField.getSelection());
}

@Test
void selectLeftYearWhenInRange() {
BibEntry leftEntry = new BibEntry().withField(StandardField.YEAR, "2005");
BibEntry rightEntry = new BibEntry().withField(StandardField.YEAR, "1700");
FieldRowViewModel yearField = new FieldRowViewModel(StandardField.YEAR, leftEntry, rightEntry, mergedEntry, fieldMergerFactory);
yearField.autoSelectBetterValue();
assertEquals(FieldRowViewModel.Selection.LEFT, yearField.getSelection());
}

public FieldRowViewModel createViewModelForField(Field field) {
return new FieldRowViewModel(field, leftEntry, rightEntry, mergedEntry, fieldMergerFactory);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.regex.Pattern;

import org.jabref.logic.integrity.YearChecker;
import org.jabref.model.strings.StringUtil;

public class YearFieldValuePlausibilityComparator extends FieldValuePlausibilityComparator {

Expand All @@ -21,28 +22,50 @@ public class YearFieldValuePlausibilityComparator extends FieldValuePlausibility

@Override
public ComparisonResult compare(String leftValue, String rightValue) {
YearChecker checker = new YearChecker();
boolean isLeftBlank = StringUtil.isBlank(leftValue);
boolean isRightBlank = StringUtil.isBlank(rightValue);
if (isLeftBlank && !isRightBlank) {
return ComparisonResult.RIGHT_BETTER;
} else if (isRightBlank && !isLeftBlank) {
return ComparisonResult.LEFT_BETTER;
} else if (isLeftBlank && isRightBlank) {
return ComparisonResult.UNDETERMINED;
}

boolean leftValid = checker.checkValue(leftValue).isEmpty();
// left and right values are not blank.

if (leftValid) {
Optional<Integer> leftYear = extractYear(leftValue);
Optional<Integer> rightYear = extractYear(rightValue);
boolean leftValueCorrectlyFormatted = YearChecker.isValueCorrectlyFormatted(leftValue);
boolean rightValueCorrectlyFormatted = YearChecker.isValueCorrectlyFormatted(rightValue);
if (leftValueCorrectlyFormatted && !rightValueCorrectlyFormatted) {
return ComparisonResult.LEFT_BETTER;
} else if (rightValueCorrectlyFormatted && !leftValueCorrectlyFormatted) {
return ComparisonResult.RIGHT_BETTER;
} else if (!leftValueCorrectlyFormatted && !rightValueCorrectlyFormatted) {
return ComparisonResult.UNDETERMINED;
}

boolean leftYearInRange = (leftYear.get() >= 1800) && (leftYear.get() <= Year.now().getValue() + 2);
// left and right values are correctly formatted.

if (leftYearInRange) {
int diff = Math.abs(leftYear.get() - rightYear.get());
if (diff > 10) {
return rightYear.get() > leftYear.get()
? ComparisonResult.RIGHT_BETTER
: ComparisonResult.LEFT_BETTER;
}
return ComparisonResult.UNDETERMINED; // years are close, undetermined
}
Integer leftYear = extractYear(leftValue).get();
Integer rightYear = extractYear(rightValue).get();
boolean leftYearInRange = (leftYear >= 1800) && (leftYear <= Year.now().getValue() + 2);
boolean rightYearInRange = (rightYear >= 1800) && (rightYear <= Year.now().getValue() + 2);
if (leftYearInRange && !rightYearInRange) {
return ComparisonResult.LEFT_BETTER;
} else if (rightYearInRange && !leftYearInRange) {
return ComparisonResult.RIGHT_BETTER;
}
return ComparisonResult.RIGHT_BETTER;
} else if (!leftYearInRange && !rightYearInRange) {
return ComparisonResult.UNDETERMINED;
}

int diff = Math.abs(leftYear - rightYear);
if (diff > 10) {
return rightYear > leftYear
? ComparisonResult.RIGHT_BETTER
: ComparisonResult.LEFT_BETTER;
}

return ComparisonResult.UNDETERMINED; // years are close, undetermined
}

/**
Expand Down
19 changes: 17 additions & 2 deletions jablib/src/main/java/org/jabref/logic/integrity/YearChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@

public class YearChecker implements ValueChecker {

private static final Predicate<String> CONTAINS_FOUR_DIGIT = Pattern.compile("([^0-9]|^)[0-9]{4}([^0-9]|$)")
.asPredicate();
private static final Predicate<String> CONTAINS_FOUR_DIGIT = Pattern.compile("([^0-9]|^)[0-9]{4}([^0-9]|$)").asPredicate();
private static final Predicate<String> ENDS_WITH_FOUR_DIGIT = Pattern.compile("[0-9]{4}$").asPredicate();
private static final String PUNCTUATION_MARKS = "[(){},.;!?<>%&$]";

Expand All @@ -37,4 +36,20 @@ public Optional<String> checkValue(String value) {

return Optional.empty();
}

public static boolean isValueCorrectlyFormatted(String value) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method duplicates logic from checkValue() which violates DRY principle. Should refactor to reuse existing validation logic to prevent maintenance issues.

if (StringUtil.isBlank(value)) {
return false;
}

if (!CONTAINS_FOUR_DIGIT.test(value.trim())) {
return false;
}

if (!ENDS_WITH_FOUR_DIGIT.test(value.replaceAll(PUNCTUATION_MARKS, ""))) {
return false;
}

return true;
}
}