diff --git a/CHANGELOG.md b/CHANGELOG.md index ca7162119e5..4e29a3dd866 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - If fetched article is already in database, then the entry merge dialog is shown. - An error message is now displayed if you try to create a group containing the keyword separator or if there is already a group with the same name. [#3075](https://github.com/JabRef/jabref/issues/3075) and [#1495](https://github.com/JabRef/jabref/issues/1495) - Integrity warnings are now directly displayed in the entry editor. +- We added the functionality to have `regex` as modifier. [#457](https://github.com/JabRef/jabref/issues/457) ### Fixed @@ -23,6 +24,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We readded the undo mechanism for changes in the entry editor [#2973](https://github.com/JabRef/jabref/issues/2973) - We fixed an issue where assigning an entry via drag and drop to a group caused JabRef to stop/freeze completely [#3036](https://github.com/JabRef/jabref/issues/3036) - We fixed the shortcut Ctrl+F for the search field. +- We fixed an issue where `title_case` and `capitalize` modifiers did not work with shorttitle. - We fixed an issue where the preferences could not be imported without a restart of JabRef [#3064](https://github.com/JabRef/jabref/issues/3064) - We fixed an issue where DEL, Ctrl+C, Ctrl+V and Ctrl+A in the search field triggered corresponding actions in the main table [#3067](https://github.com/JabRef/jabref/issues/3067) - We fixed an issue where JabRef freezed when editing an assigned file in the `General`-Tab [#2930, comment](https://github.com/JabRef/jabref/issues/2930#issuecomment-311050976) diff --git a/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtil.java b/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtil.java index a9757c22f30..7e1a1c74d72 100644 --- a/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtil.java +++ b/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtil.java @@ -737,7 +737,7 @@ private static String getAddition(int number) { * Determines "number" words out of the "title" field in the given BibTeX entry */ public static String getTitleWords(int number, String title) { - return keepLettersAndDigitsOnly(getTitleWordsWithSpaces(number, title)); + return getTitleWordsWithSpaces(number, title); } /** diff --git a/src/main/java/org/jabref/logic/formatter/Formatters.java b/src/main/java/org/jabref/logic/formatter/Formatters.java index 862f97d65a9..9f682ae5130 100644 --- a/src/main/java/org/jabref/logic/formatter/Formatters.java +++ b/src/main/java/org/jabref/logic/formatter/Formatters.java @@ -16,6 +16,7 @@ import org.jabref.logic.formatter.bibtexfields.NormalizeNamesFormatter; import org.jabref.logic.formatter.bibtexfields.NormalizePagesFormatter; import org.jabref.logic.formatter.bibtexfields.OrdinalsToSuperscriptFormatter; +import org.jabref.logic.formatter.bibtexfields.RegexFormatter; import org.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter; import org.jabref.logic.formatter.bibtexfields.UnicodeToLatexFormatter; import org.jabref.logic.formatter.bibtexfields.UnitsToLatexFormatter; @@ -56,6 +57,7 @@ public class Formatters { new NormalizeNamesFormatter(), new NormalizePagesFormatter(), new OrdinalsToSuperscriptFormatter(), + new RegexFormatter(), new RemoveBracesFormatter(), new UnitsToLatexFormatter(), new EscapeUnderscoresFormatter() @@ -63,12 +65,24 @@ public class Formatters { public static final List ALL = new ArrayList<>(); + private static final String REGEX = "regex"; + + private static final int LENGTH_OF_REGEX_PREFIX = REGEX.length(); + private Formatters() { } public static Optional getFormatterForModifier(String modifier) { Objects.requireNonNull(modifier); - Optional formatter = ALL.stream().filter(f -> f.getKey().equals(modifier)).findAny(); + Optional formatter; + + if (modifier.matches("regex.*")) { + String regex = modifier.substring(LENGTH_OF_REGEX_PREFIX); + RegexFormatter.setRegex(regex); + formatter = ALL.stream().filter(f -> f.getKey().equals("regex")).findAny(); + } else { + formatter = ALL.stream().filter(f -> f.getKey().equals(modifier)).findAny(); + } if (formatter.isPresent()) { return formatter; } diff --git a/src/main/java/org/jabref/logic/formatter/bibtexfields/RegexFormatter.java b/src/main/java/org/jabref/logic/formatter/bibtexfields/RegexFormatter.java new file mode 100644 index 00000000000..3ad3b763676 --- /dev/null +++ b/src/main/java/org/jabref/logic/formatter/bibtexfields/RegexFormatter.java @@ -0,0 +1,105 @@ +package org.jabref.logic.formatter.bibtexfields; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.jabref.logic.l10n.Localization; +import org.jabref.model.cleanup.Formatter; + +public class RegexFormatter implements Formatter { + + private static final Pattern PATTERN_ESCAPED_OPENING_CURLY_BRACE = Pattern.compile("\\\\\\{"); + + private static final Pattern PATTERN_ESCAPED_CLOSING_CURLY_BRACE = Pattern.compile("\\\\\\}"); + + // RegEx to match {...} + // \\ is required to have the { interpreted as character + // ? is required to disable the aggressive match + private static final Pattern PATTERN_ENCLOSED_IN_CURLY_BRACES = Pattern.compile("(\\{.*?})"); + + // Magic arbitrary unicode char, which will never appear in bibtex files + private static final String PLACEHOLDER_FOR_PROTECTED_GROUP = Character.toString('\u0A14'); + + private static final String PLACEHOLDER_FOR_OPENING_CURLY_BRACE = Character.toString('\u0A15'); + + private static final String PLACEHOLDER_FOR_CLOSING_CURLY_BRACE = Character.toString('\u0A16'); + + private static final String QUOTE_AND_OPENING_BRACE = "\"("; + + private static final int LENGTH_OF_QUOTE_AND_OPENING_BRACE = QUOTE_AND_OPENING_BRACE.length(); + + private static final String CLOSING_BRACE_AND_QUOTE = ")\""; + + private static final int LENGTH_OF_CLOSING_BRACE_AND_QUOTE = CLOSING_BRACE_AND_QUOTE.length(); + + // stores the regex set by setRegex + private static String[] regex; + + @Override + public String getName() { + return Localization.lang("regular_expression"); + } + + @Override + public String getKey() { + return "regex"; + } + + private String replaceHonoringProtectedGroups(final String input) { + Matcher matcher = PATTERN_ENCLOSED_IN_CURLY_BRACES.matcher(input); + + List replaced = new ArrayList<>(); + while (matcher.find()) { + replaced.add(matcher.group(1)); + } + String workingString = matcher.replaceAll(PLACEHOLDER_FOR_PROTECTED_GROUP); + workingString = workingString.replaceAll(RegexFormatter.regex[0], RegexFormatter.regex[1]); + + for (String r : replaced) { + workingString = workingString.replaceFirst(PLACEHOLDER_FOR_PROTECTED_GROUP, r); + } + return workingString; + } + + @Override + public String format(final String input) { + Objects.requireNonNull(input); + if (regex == null) { + return input; + } + + Matcher matcherOpeningCurlyBrace = PATTERN_ESCAPED_OPENING_CURLY_BRACE.matcher(input); + final String openingCurlyBraceReplaced = matcherOpeningCurlyBrace.replaceAll(PLACEHOLDER_FOR_OPENING_CURLY_BRACE); + + Matcher matcherClosingCurlyBrace = PATTERN_ESCAPED_CLOSING_CURLY_BRACE.matcher(openingCurlyBraceReplaced); + final String closingCurlyBraceReplaced = matcherClosingCurlyBrace.replaceAll(PLACEHOLDER_FOR_CLOSING_CURLY_BRACE); + + final String regexApplied = replaceHonoringProtectedGroups(closingCurlyBraceReplaced); + + return regexApplied + .replaceAll(PLACEHOLDER_FOR_OPENING_CURLY_BRACE, "\\\\{") + .replaceAll(PLACEHOLDER_FOR_CLOSING_CURLY_BRACE, "\\\\}"); + } + + @Override + public String getDescription() { + return Localization.lang("Add a regular expression for the key pattern."); + } + + @Override + public String getExampleInput() { + return "Please replace the spaces"; + } + + public static void setRegex(String rex) { + // formatting is like ("exp1","exp2"), we want to remove (" and ") + String rexToSet = rex; + rexToSet = rexToSet.substring(LENGTH_OF_QUOTE_AND_OPENING_BRACE, rexToSet.length() - LENGTH_OF_CLOSING_BRACE_AND_QUOTE); + String[] parts = rexToSet.split("\",\""); + regex = parts; + } + +} diff --git a/src/main/java/org/jabref/logic/formatter/casechanger/SentenceCaseFormatter.java b/src/main/java/org/jabref/logic/formatter/casechanger/SentenceCaseFormatter.java index 91082d76e9e..87342d63b3d 100644 --- a/src/main/java/org/jabref/logic/formatter/casechanger/SentenceCaseFormatter.java +++ b/src/main/java/org/jabref/logic/formatter/casechanger/SentenceCaseFormatter.java @@ -16,7 +16,7 @@ public String getKey() { } /** - * Converts the first character of the first word of the given string to upper case (and the remaining characters of the first word to lower case), but does not change anything if word starts with "{" + * Converts the first character of the first word of the given string to upper case (and the remaining characters of the first word to lower case) and changes other words to lower case, but does not change anything if word starts with "{" */ @Override public String format(String input) { diff --git a/src/main/resources/l10n/JabRef_da.properties b/src/main/resources/l10n/JabRef_da.properties index 6041f99e664..e33a26c6035 100644 --- a/src/main/resources/l10n/JabRef_da.properties +++ b/src/main/resources/l10n/JabRef_da.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=Stien_behøver_ikke_at_være_p Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Tilføj_en_kompileret_Importer-klasse_fra_en_ZIP-fil. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=ZIP-filen_behøver_ikke_at_være_i_din_classpath. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group= Add_from_folder=Tilføj_fra_mappe diff --git a/src/main/resources/l10n/JabRef_de.properties b/src/main/resources/l10n/JabRef_de.properties index 8484ed0707e..446009f9fcd 100644 --- a/src/main/resources/l10n/JabRef_de.properties +++ b/src/main/resources/l10n/JabRef_de.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=Das_Verzeichnis_muss_nicht_im_K Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Füge_eine_(kompilierte)_externe_Importer_Klasse_aus_Verzeichnis_hinzu. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=Das_Verzeichnis_muss_nicht_im_Klassenpfad_von_JabRef_enthalten_sein. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group=Ausgewählte_Einträge_zu_dieser_Gruppe_hinzufügen Add_from_folder=Aus_Klassenpfad_hinzufügen diff --git a/src/main/resources/l10n/JabRef_el.properties b/src/main/resources/l10n/JabRef_el.properties index c720bd96c8d..fcda3898416 100644 --- a/src/main/resources/l10n/JabRef_el.properties +++ b/src/main/resources/l10n/JabRef_el.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=The_path_need_not_be_on_the_cla Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.= The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group= Add_from_folder=Προσθήκη_από_φάκελο diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index b11658faa84..4fa4b7aa5ce 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=The_path_need_not_be_on_the_cla Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef. +Add_a_regular_expression_for_the_key_pattern.=Add_a_regular_expression_for_the_key_pattern. + Add_selected_entries_to_this_group=Add_selected_entries_to_this_group Add_from_folder=Add_from_folder diff --git a/src/main/resources/l10n/JabRef_es.properties b/src/main/resources/l10n/JabRef_es.properties index 23700baaae2..d728f351ef4 100644 --- a/src/main/resources/l10n/JabRef_es.properties +++ b/src/main/resources/l10n/JabRef_es.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=La_ruta_no_debe_estar_en_la_cla Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Añadir_una_clase_personalizada_(compilada)_Importer_desde_un_archivo_ZIP. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=El_archivo_ZIP_no_tiene_por_qué_estar_en_la_classpath_de_JabRef. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group=Añadir_entradas_seleccionadas_a_este_grupo Add_from_folder=Añadir_desde_carpeta diff --git a/src/main/resources/l10n/JabRef_fa.properties b/src/main/resources/l10n/JabRef_fa.properties index ba9dc4ea2e1..69d8c4b81d6 100644 --- a/src/main/resources/l10n/JabRef_fa.properties +++ b/src/main/resources/l10n/JabRef_fa.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.= Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.= The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.= +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group= Add_from_folder= diff --git a/src/main/resources/l10n/JabRef_fr.properties b/src/main/resources/l10n/JabRef_fr.properties index 49a05fe0e87..81d389c341e 100644 --- a/src/main/resources/l10n/JabRef_fr.properties +++ b/src/main/resources/l10n/JabRef_fr.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=Le_chemin_n'a_pas_besoin_d'êtr Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Ajouter_une_classe_Importer_personnalisée_(compilée)_à_partir_d'une_archive_ZIP. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=L'archive_ZIP_n'a_pas_besoin_d'être_dans_le_chemin_de_classe_de_JabRef. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group=Ajouter_les_entrées_sélectionnées_à_ce_groupe Add_from_folder=Ajouter_à_partir_du_répertoire diff --git a/src/main/resources/l10n/JabRef_in.properties b/src/main/resources/l10n/JabRef_in.properties index 5790c469301..1421d85a28c 100644 --- a/src/main/resources/l10n/JabRef_in.properties +++ b/src/main/resources/l10n/JabRef_in.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=Lokasi_tidak_harus_pada_lokasi_ Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Tambah_suaian_kelas_Importer_dari_arsip_ZIP. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=Lokasi_arsip_ZIP_tidak_harus_dalam_lokasi_kelas_JabRef. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group= Add_from_folder=Tambah_dari_folder diff --git a/src/main/resources/l10n/JabRef_it.properties b/src/main/resources/l10n/JabRef_it.properties index 8e4e488b70f..44d83d9d210 100644 --- a/src/main/resources/l10n/JabRef_it.properties +++ b/src/main/resources/l10n/JabRef_it.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=Il_percorso_non_deve_necessaria Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Aggiungi_una_classe_Importer_personalizzata_(compilata)_da_un_archivio_ZIP. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=L'archivio_ZIP_non_deve_necessariamente_essere_nel_classpath_di_JabRef. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group=Aggiungi_le_voci_selezionate_a_questo_gruppo Add_from_folder=Aggiungi_da_una_cartella diff --git a/src/main/resources/l10n/JabRef_ja.properties b/src/main/resources/l10n/JabRef_ja.properties index 75e86cd37e3..e1d884fa2ce 100644 --- a/src/main/resources/l10n/JabRef_ja.properties +++ b/src/main/resources/l10n/JabRef_ja.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=このパスは、JabRefのク Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=(コンパイルした)ユーザー定義ImportFormatクラスをZIP書庫から追加します。 The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=このZIP書庫は、JabRefのクラスパスにあるとは限りません。 +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group= Add_from_folder=フォルダから追加 diff --git a/src/main/resources/l10n/JabRef_nl.properties b/src/main/resources/l10n/JabRef_nl.properties index 61faa959492..b1ca0f6dbe2 100644 --- a/src/main/resources/l10n/JabRef_nl.properties +++ b/src/main/resources/l10n/JabRef_nl.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=Het_pad_moet_niet_in_het_classp Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Voeg_een_(gecompileerde)_externe_Importer_klasse_van_een_ZIP-archief_toe. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=Het_pad_moet_niet_in_het_classpath_van_JabRef_staan. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group= Add_from_folder=Voeg_toe_uit_map diff --git a/src/main/resources/l10n/JabRef_no.properties b/src/main/resources/l10n/JabRef_no.properties index 0324a734abc..8282809df9b 100644 --- a/src/main/resources/l10n/JabRef_no.properties +++ b/src/main/resources/l10n/JabRef_no.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=Stien_trenger_ikke_\u00e5_v\u00 Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Legg_til_en_(kompilert)_egendefinert_Importer-klasse_fra_en_zip-fil. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=ZIP-filen_trenger_ikke_\u00e5_v\u00e6re_p\u00e5_JabRefs_classpath. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group= Add_from_folder=Legg_til_fra_mappe diff --git a/src/main/resources/l10n/JabRef_pt_BR.properties b/src/main/resources/l10n/JabRef_pt_BR.properties index 33ab7ff9e95..669d0c1da67 100644 --- a/src/main/resources/l10n/JabRef_pt_BR.properties +++ b/src/main/resources/l10n/JabRef_pt_BR.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=O_caminho_não_precisa_estar_no Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Adicionar_uma_classe_Importer_customizada_(compilada)_a_partir_de_um_arquivo_zip. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=O_arquivo_zip_não_precisa_estar_no_classpath_do_JabRef. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group= Add_from_folder=Adicionar_a_partir_de_uma_pasta diff --git a/src/main/resources/l10n/JabRef_ru.properties b/src/main/resources/l10n/JabRef_ru.properties index b35ae21e2ee..ef66c1f6d9e 100644 --- a/src/main/resources/l10n/JabRef_ru.properties +++ b/src/main/resources/l10n/JabRef_ru.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=Путь_может_не_сов Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Добавить_(скомпил.)_пользовательский_класс_Importer_из_ZIP-архива. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=ZIP-архив_может_не_совпадать_с_путем_классов_JabRef. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group= Add_from_folder=Добавить_из_папки diff --git a/src/main/resources/l10n/JabRef_sv.properties b/src/main/resources/l10n/JabRef_sv.properties index cad1056751e..7a3f81935f6 100644 --- a/src/main/resources/l10n/JabRef_sv.properties +++ b/src/main/resources/l10n/JabRef_sv.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.= Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Lägg_till_en_(kompilerad)_Importer-klass_från_en_zip-fil. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.= +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group= Add_from_folder=Lägg_till_från_mapp diff --git a/src/main/resources/l10n/JabRef_tr.properties b/src/main/resources/l10n/JabRef_tr.properties index 630e76b1a59..159c9b2c096 100644 --- a/src/main/resources/l10n/JabRef_tr.properties +++ b/src/main/resources/l10n/JabRef_tr.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=Yolun_JabRef'in_sınıf_yolunda Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Bir_ZIP_arşivinden_(derlenmiş)_özel_İçeAlmaBiçemi_sınıfı_ekle. The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=Yolun_JabRef'in_sınıf_yolunda_olması_gerekmez. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group=Seçili_girdileri_bu_gruba_ekle Add_from_folder=Klasörden_ekle diff --git a/src/main/resources/l10n/JabRef_vi.properties b/src/main/resources/l10n/JabRef_vi.properties index 9f960cff6a8..ebfc8efef59 100644 --- a/src/main/resources/l10n/JabRef_vi.properties +++ b/src/main/resources/l10n/JabRef_vi.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=Đường_dẫn_không_được Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Thêm_một_lớp_ĐịnhdạngNhập_tùy_biến_(được_biên_dịch)_từ_một_tập_tin-zip._ The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=Tập_tin-zip_không_được_trùng_với_đường_dẫn_lớp_của_JabRef. +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group= Add_from_folder=Thêm_từ_thư_mục diff --git a/src/main/resources/l10n/JabRef_zh.properties b/src/main/resources/l10n/JabRef_zh.properties index cac4a529d81..4a01101ba3d 100644 --- a/src/main/resources/l10n/JabRef_zh.properties +++ b/src/main/resources/l10n/JabRef_zh.properties @@ -51,6 +51,8 @@ The_path_need_not_be_on_the_classpath_of_JabRef.=该路径不需要在_JabRef_ Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=从一个_ZIP_压缩包中添加(编译好的)自定义导入类。 The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=该_ZIP_压缩包不需要在_JabRef_的_classpath_下。 +Add_a_regular_expression_for_the_key_pattern.= + Add_selected_entries_to_this_group=添加选定记录到该组 Add_from_folder=从文件夹中添加 diff --git a/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtilTest.java b/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtilTest.java index f9e5fd5e03b..16f33e21965 100644 --- a/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtilTest.java +++ b/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtilTest.java @@ -674,20 +674,20 @@ public void veryShortTitle() { public void shortTitle() { // shortTitle is getTitleWords with "3" as count int count = 3; - assertEquals("applicationmigrationeffort", + assertEquals("application migration effort", BibtexKeyPatternUtil.getTitleWords(count, TITLE_STRING_ALL_LOWER_FOUR_SMALL_WORDS_ONE_EN_DASH)); - assertEquals("BPELconformancein", BibtexKeyPatternUtil.getTitleWords(count, + assertEquals("BPEL conformance in", BibtexKeyPatternUtil.getTitleWords(count, TITLE_STRING_ALL_LOWER_FIRST_WORD_IN_BRACKETS_TWO_SMALL_WORDS_SMALL_WORD_AFTER_COLON)); - assertEquals("ProcessViewingPatterns", BibtexKeyPatternUtil.getTitleWords(count, TITLE_STRING_CASED)); - assertEquals("BPMNConformancein", + assertEquals("Process Viewing Patterns", BibtexKeyPatternUtil.getTitleWords(count, TITLE_STRING_CASED)); + assertEquals("BPMN Conformance in", BibtexKeyPatternUtil.getTitleWords(count, TITLE_STRING_CASED_ONE_UPPER_WORD_ONE_SMALL_WORD)); - assertEquals("TheDifferenceBetween", BibtexKeyPatternUtil.getTitleWords(count, + assertEquals("The Difference Between", BibtexKeyPatternUtil.getTitleWords(count, TITLE_STRING_CASED_TWO_SMALL_WORDS_SMALL_WORD_AT_THE_BEGINNING)); - assertEquals("CloudComputingThe", + assertEquals("Cloud Computing: The", BibtexKeyPatternUtil.getTitleWords(count, TITLE_STRING_CASED_TWO_SMALL_WORDS_SMALL_WORD_AFTER_COLON)); - assertEquals("TowardsChoreographybased", + assertEquals("Towards Choreography based", BibtexKeyPatternUtil.getTitleWords(count, TITLE_STRING_CASED_TWO_SMALL_WORDS_ONE_CONNECTED_WORD)); - assertEquals("OntheMeasurement", + assertEquals("On the Measurement", BibtexKeyPatternUtil.getTitleWords(count, TITLE_STRING_CASED_FOUR_SMALL_WORDS_TWO_CONNECTED_WORDS)); } @@ -808,7 +808,7 @@ public void testApplyModifiers() { BibEntry entry = new BibEntry(); entry.setField("title", "Green Scheduling of Whatever"); assertEquals("GSo", BibtexKeyPatternUtil.makeLabel(entry, "shorttitleINI", ',', new BibDatabase())); - assertEquals("GreenSchedulingof", BibtexKeyPatternUtil.makeLabel(entry, "shorttitle", + assertEquals("Green Scheduling of", BibtexKeyPatternUtil.makeLabel(entry, "shorttitle", ',', new BibDatabase())); } diff --git a/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java b/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java index 809b4d16ee8..8098382567f 100644 --- a/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java +++ b/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java @@ -123,19 +123,40 @@ public void generateDefaultKeyFirstTwoAlreadyExists() { } @Test - public void generateDefaultKeyLowerModified() { + public void generateKeyAuthLowerModified() { bibtexKeyPattern.setDefaultValue("[auth:lower][year]"); BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); assertEquals(Optional.of("doe2016"), entry.getCiteKeyOptional()); } @Test - public void generateDefaultKeyUpperModified() { + public void generateKeyAuthUpperModified() { bibtexKeyPattern.setDefaultValue("[auth:upper][year]"); BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); assertEquals(Optional.of("DOE2016"), entry.getCiteKeyOptional()); } + @Test + public void generateKeyAuthTitleCaseModified() { + bibtexKeyPattern.setDefaultValue("[auth:title_case][year]"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("Doe2016"), entry.getCiteKeyOptional()); + } + + @Test + public void generateKeyAuthSentenceCaseModified() { + bibtexKeyPattern.setDefaultValue("[auth:sentence_case][year]"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("Doe2016"), entry.getCiteKeyOptional()); + } + + @Test + public void generateKeyAuthCapitalizeModified() { + bibtexKeyPattern.setDefaultValue("[auth:capitalize][year]"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("Doe2016"), entry.getCiteKeyOptional()); + } + @Test public void generateDefaultKeyFixedValue() { bibtexKeyPattern.setDefaultValue("[auth]Test[year]"); @@ -208,6 +229,46 @@ public void generateKeyShorttitle() { assertEquals(Optional.of("Anawesomepaper"), entry.getCiteKeyOptional()); } + @Test + public void generateKeyShorttitleLowerModified() { + bibtexKeyPattern.setDefaultValue("[shorttitle:lower]"); + entry.setField("title", "An aweSOme Paper on JabRef"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("anawesomepaper"), entry.getCiteKeyOptional()); + } + + @Test + public void generateKeyShorttitleUpperModified() { + bibtexKeyPattern.setDefaultValue("[shorttitle:upper]"); + entry.setField("title", "An aweSOme Paper on JabRef"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("ANAWESOMEPAPER"), entry.getCiteKeyOptional()); + } + + @Test + public void generateKeyShorttitleTitleCaseModified() { + bibtexKeyPattern.setDefaultValue("[shorttitle:title_case]"); + entry.setField("title", "An aweSOme Paper on JabRef"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("AnAwesomePaper"), entry.getCiteKeyOptional()); + } + + @Test + public void generateKeyShorttitleSentenceCaseModified() { + bibtexKeyPattern.setDefaultValue("[shorttitle:sentence_case]"); + entry.setField("title", "An aweSOme Paper on JabRef"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("Anawesomepaper"), entry.getCiteKeyOptional()); + } + + @Test + public void generateKeyShorttitleCapitalizeModified() { + bibtexKeyPattern.setDefaultValue("[shorttitle:capitalize]"); + entry.setField("title", "An aweSOme Paper on JabRef"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("AnAwesomePaper"), entry.getCiteKeyOptional()); + } + @Test public void generateKeyVeryshorttitle() { bibtexKeyPattern.setDefaultValue("[veryshorttitle]"); @@ -215,6 +276,46 @@ public void generateKeyVeryshorttitle() { assertEquals(Optional.of("awesome"), entry.getCiteKeyOptional()); } + @Test + public void generateKeyVeryshorttitleLowerModified() { + bibtexKeyPattern.setDefaultValue("[veryshorttitle:lower]"); + entry.setField("title", "An aweSOme Paper on JabRef"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("awesome"), entry.getCiteKeyOptional()); + } + + @Test + public void generateKeyVeryshorttitleUpperModified() { + bibtexKeyPattern.setDefaultValue("[veryshorttitle:upper]"); + entry.setField("title", "An aweSOme Paper on JabRef"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("AWESOME"), entry.getCiteKeyOptional()); + } + + @Test + public void generateKeyVeryshorttitleTitleCaseModified() { + bibtexKeyPattern.setDefaultValue("[veryshorttitle:title_case]"); + entry.setField("title", "An aweSOme Paper on JabRef"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("Awesome"), entry.getCiteKeyOptional()); + } + + @Test + public void generateKeyVeryshorttitleSentenceCaseModified() { + bibtexKeyPattern.setDefaultValue("[veryshorttitle:sentence_case]"); + entry.setField("title", "An aweSOme Paper on JabRef"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("Awesome"), entry.getCiteKeyOptional()); + } + + @Test + public void generateKeyVeryshorttitleCapitalizeModified() { + bibtexKeyPattern.setDefaultValue("[veryshorttitle:capitalize]"); + entry.setField("title", "An aweSOme Paper on JabRef"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("Awesome"), entry.getCiteKeyOptional()); + } + @Test public void generateKeyShorttitleINI() { bibtexKeyPattern.setDefaultValue("[shorttitleINI]"); @@ -286,6 +387,14 @@ public void generateKeyAuthIniMany() { assertEquals(Optional.of("DoeSmiWon"), entry.getCiteKeyOptional()); } + @Test + public void generateKeyTitleRegexe() { + bibtexKeyPattern.setDefaultValue("[title:regex(\" \",\"-\")]"); + entry.setField("title", "Please replace the spaces"); + BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences); + assertEquals(Optional.of("Please-Replace-the-Spaces"), entry.getCiteKeyOptional()); + } + @Test public void generateKeyTitleTitleCase() { bibtexKeyPattern.setDefaultValue("[title:title_case]"); diff --git a/src/test/java/org/jabref/logic/formatter/FormatterTest.java b/src/test/java/org/jabref/logic/formatter/FormatterTest.java index ecb7a695b06..1fdc8231a35 100644 --- a/src/test/java/org/jabref/logic/formatter/FormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/FormatterTest.java @@ -13,6 +13,7 @@ import org.jabref.logic.formatter.bibtexfields.NormalizeNamesFormatter; import org.jabref.logic.formatter.bibtexfields.NormalizePagesFormatter; import org.jabref.logic.formatter.bibtexfields.OrdinalsToSuperscriptFormatter; +import org.jabref.logic.formatter.bibtexfields.RegexFormatter; import org.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter; import org.jabref.logic.formatter.bibtexfields.UnicodeToLatexFormatter; import org.jabref.logic.formatter.bibtexfields.UnitsToLatexFormatter; @@ -123,6 +124,7 @@ public static Collection instancesToTest() { new Object[]{new NormalizePagesFormatter()}, new Object[]{new OrdinalsToSuperscriptFormatter()}, new Object[]{new ProtectTermsFormatter()}, + new Object[]{new RegexFormatter()}, new Object[]{new RemoveBracesFormatter()}, new Object[]{new SentenceCaseFormatter()}, new Object[]{new TitleCaseFormatter()}, diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java new file mode 100644 index 00000000000..4c85a519f90 --- /dev/null +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java @@ -0,0 +1,66 @@ +package org.jabref.logic.formatter.bibtexfields; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} + */ +public class RegexFormatterTest { + + private RegexFormatter formatter; + + @Before + public void setUp() { + formatter = new RegexFormatter(); + } + + @Test + public void spacesReplacedCorrectly() { + String regexInput = "(\" \",\"-\")"; + formatter.setRegex(regexInput); + Assert.assertEquals("replace-all-spaces", formatter.format("replace all spaces")); + } + + @Test + public void protectedSpacesNotReplacedInSingleProtectedBlock() { + String regexInput = "(\" \",\"-\")"; + formatter.setRegex(regexInput); + Assert.assertEquals("replace-spaces-{not these ones}", formatter.format("replace spaces {not these ones}")); + } + + @Test + public void protectedSpacesNotReplacedInTwoProtectedBlocks() { + String regexInput = "(\" \",\"-\")"; + formatter.setRegex(regexInput); + Assert.assertEquals("replace-spaces-{not these ones}-{or these ones}-but-these-ones", formatter.format("replace spaces {not these ones} {or these ones} but these ones")); + } + + @Test + public void escapedBracesAreNotReplaced() { + String regexInput = "(\" \",\"-\")"; + formatter.setRegex(regexInput); + Assert.assertEquals("replace-spaces-\\{-these-ones\\}-and-these-ones", formatter.format("replace spaces \\{ these ones\\} and these ones")); + } + + @Test + public void escapedBracesAreNotReplacedInTwoCases() { + String regexInput = "(\" \",\"-\")"; + formatter.setRegex(regexInput); + Assert.assertEquals("replace-spaces-\\{-these-ones\\},-these-ones,-and-\\{-these-ones\\}", formatter.format("replace spaces \\{ these ones\\}, these ones, and \\{ these ones\\}")); + } + + @Test + public void escapedBracesAreNotReplacedAndProtectionStillWorks() { + String regexInput = "(\" \",\"-\")"; + formatter.setRegex(regexInput); + Assert.assertEquals("replace-spaces-{not these ones},-these-ones,-and-\\{-these-ones\\}", formatter.format("replace spaces {not these ones}, these ones, and \\{ these ones\\}")); + } + + @Test + public void formatExample() { + Assert.assertEquals("Please-replace-the-spaces", formatter.format(formatter.getExampleInput())); + } + +}