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

Made the code more stable and resilient to wrong inputs, added example .html-file of how to use it #35

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
4 changes: 3 additions & 1 deletion SAMPLE.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ var bibtexParse = require('bibtex-parse-js');

var sample = bibtexParse.toJSON('@article{sample1,title={sample title}}');

# Will conolse log:
/*
# Will console log:
#
# [ { citationKey: 'SAMPLE1',
# entryType: 'ARTICLE',
# entryTags: { TITLE: 'sample title' } } ]
#
*/
console.log(sample);
103 changes: 96 additions & 7 deletions bibtexParse.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,12 @@
return this.value_quotes();
} else {
var k = this.key();
if (k.match("^[0-9]+$"))
return k;
if (k.match("^[0-9]+\n*$"))
return parseInt(k);
else if (this.months.indexOf(k.toLowerCase()) >= 0)
return k.toLowerCase();
else
throw "Value expected: single_value" + this.input.substring(start) + ' for key: ' + k;
throw "Value expected: single_value " + this.input.substring(start) + ' for key: ' + k;

};
};
Expand All @@ -190,7 +190,11 @@
this.match("#");
values.push(this.single_value());
};
return values.join("");
if(values.length == 1) {
return values[0];
} else {
return values.join("");
}
};

this.key = function(optional) {
Expand Down Expand Up @@ -238,8 +242,16 @@
break;
}
;
kv = this.key_equals_value();
this.currentEntry['entryTags'][kv[0]] = kv[1];
try {
kv = this.key_equals_value();
this.currentEntry['entryTags'][kv[0]] = kv[1];
} catch (e) {
if(("" + e).includes("Value expected, equals sign missing: key_equals_value")) {
console.warn("Warning: ignoring line");
} else {
throw new Error(e);
}
}
};
};

Expand Down Expand Up @@ -302,7 +314,15 @@
} else {
this.entry(d);
}
this.match("}");
try {
this.match("}");
} catch (e) {
if(("" + e).includes("Token mismatch: match")) {
console.warn(e + ", ignoring line");
} else {
throw new Error(e);
}
}
};

this.alernativeCitationKey();
Expand All @@ -311,6 +331,75 @@

exports.toJSON = function(bibtex) {
var b = new BibtexParser();
function cleanBibtex(bibtex_code) {
// searches for lines that should begin with @, but dont, and add @ for resiliency
var at_regex = /(\s+|^)(\w+\{)/ig;
bibtex_code = bibtex_code.replace(at_regex, (match) => `${match[1].replace(/[\n\r\R]*/, "")}\n@${match.replace(/[\n\r\R]*/, "")}`);

// remove spaces before @ at beginning of line
var space_regex = /^\s*@/g;
bibtex_code = bibtex_code.replace(space_regex, "@");

var search_missing_commas_regex_stage_one = /(.*=.*)/g;
bibtex_code = bibtex_code.replace(search_missing_commas_regex_stage_one, "$1,");

var search_missing_commas_regex_stage_two = /(,\s*)+\s*$/g;
bibtex_code = bibtex_code.replace(search_missing_commas_regex_stage_two, ",\n");

var find_unfinished_double_quotes = /(=\s*"[^"]*?),+/g;
bibtex_code = bibtex_code.replace(find_unfinished_double_quotes, `$1",`);

var find_unfinished_bracket_quotes = /(=\s*\{[^\}]*?),+/g;
bibtex_code = bibtex_code.replace(find_unfinished_bracket_quotes, `$1},`);

var find_missing_quotation = /(.*=)([^\{"'].*?[^\}"']),/g;
bibtex_code = bibtex_code.replace(find_missing_quotation, `$1{$2},`);

var find_missing_bracket_quote_start = /(.*=)([^\{].*?\}),/g;
bibtex_code = bibtex_code.replace(find_missing_bracket_quote_start, `$1{$2,`);

var find_missing_article_type = /^\s*(?<=@)([a-zA-Z0-9_]*)/g;
if(bibtex_code.match(find_missing_article_type)) {
bibtex_code = bibtex_code.replace(find_missing_article_type, `@article{$1`);
console.log("Found no article type, added @article");
}

var remove_double_commas = /,,+/g
bibtex_code = bibtex_code.replace(remove_double_commas, ",\n");

console.log(bibtex_code);

var lines = bibtex_code.split(/[\n\r]/);

function line_could_be_valid_syntax (line) {
if(line.match("^\s*@")) {
return true;
} else if(line.match("=")) {
return true;
} else if(line.match("}")) {
return true;
} else if(line.match(/^\s*$/)) {
return true;
} else {
return false;
}
}

var new_lines = [];

for (var i = 0; i < lines.length; i++) {
if(line_could_be_valid_syntax(lines[i])) {
new_lines.push(lines[i]);
} else {
console.warn("The line " + lines[i] + " does not seem to contain a valid bibtex line");
}
}

return new_lines.join("\n");
}

bibtex = cleanBibtex(bibtex);

b.setInput(bibtex);
b.bibtex();
return b.entries;
Expand Down
166 changes: 166 additions & 0 deletions example_site/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<!DOCTYPE html>
<html>
<head>
<title>BibTeX Parser</title>
</head>
<body>
<script src="../bibtexParse.js"></script>

<h1>BibTeX to JSON Parser</h1>

<label for="bibtexInput">Enter BibTeX Code:</label>
<textarea id="bibtexInput" rows="5" cols="50">
@article{sample1,
title={sample title},
author="sample title"
}

@online{sample2,
title={sample title 2},
author="sample title 2",
year=1995,
url="https://google.de"
}

online{sample2,
title={sample title 2},
author="sample title 2"
year=1995,
url="https://google.de"
}


online{sample3,
title={sample title 3,
author="sample title 3"
year=19909,
url="https://google.de
}

online{sample4,
title=sample title 4,
author=sample title 4
year=199,
url="https://google.de
}

online{sample5,
title=sample title 5},
author=sample title 5}
year=199
url="https://google.de,,,

sfdfs

asdasdasd={12312
}

asdasdasdasd asd oaskfdösdfr234r 243r wef

@book{sample2,
title={Buch ohne Autor},
year={2019},
}

@article{sample#3,
title={Unerwartete Zeichen im Schlüssel},
author={Autor 3},
year={2018},
}

@inproceedings{sample4,
title={Titel mit falschen "Anführungszeichen"},
author={Autor 4},
year={2017},
}

@online{sample5,
title={Ungültiges Feld},
author={Autor 5},
year={2021},
url="https://example.com",
publisher="Verlag 5",

sample1,
title={Fehlender Schlüssel},
author={Autor 1},
year={2022},
url="https://example.com",
}

@book{sample6,
title={Buch mit fehlendem Jahr},
author={Autor 6},
url="https://example.com",
}

@journal{sample7,
title={Artikel mit falschem Eintragstyp},
author={Autor 7},
year={2015},
}

@article{sample8,
title={Artikel mit Sonderzeichen wie !@# in Titel},
author={Autor 8},
year={2016},
}

@book{sample9,
title={Buch 1},
author={Autor 9},
year={2020},
}

@book{sample9,
title={Buch 2},
author={Autor 10},
year={2021},
}

@online{sample10,
title={Online-Ressource mit unvollständiger URL},
author={Autor 11},
year={2019},
url="example.com",
}
fsdfsdfd
</textarea>
<button onclick="parseBibtex()">Parse</button>

<h1>JSON</h1>
<pre id="outputDiv"></pre>
<h1>BibTeX</h1>
<pre id="bibtexDiv"></pre>
<div id="errorDiv" style="color: red;"></div>

<script>
function parseBibtex() {
try {
const bibtexInput = document.getElementById('bibtexInput').value;
const parsedJSON = bibtexParse.toJSON(bibtexInput);

if (parsedJSON) {
const prettyJSON = JSON.stringify(parsedJSON, null, 2);
document.getElementById('outputDiv').textContent = prettyJSON;
document.getElementById('bibtexDiv').textContent = bibtexParse.toBibtex(parsedJSON, 0);
document.getElementById('errorDiv').textContent = "";
return parsedJSON;
} else {
document.getElementById('outputDiv').textContent = "Invalid BibTeX input.";
document.getElementById('bibtexDiv').textContent = "";
document.getElementById('errorDiv').textContent = "";
}
} catch (error) {
console.warn("Error parsing BibTeX:", error);
document.getElementById('outputDiv').textContent = "An error occurred while parsing the input.";
document.getElementById('bibtexDiv').textContent = "";
document.getElementById('errorDiv').textContent = "Error: " + error.message;
}

return {};
}
</script>
</body>
</html>