Skip to content

Commit

Permalink
ReplaceStrongs: renumber from Logos links
Browse files Browse the repository at this point in the history
  • Loading branch information
schierlm committed May 6, 2024
1 parent 1f6be4a commit 96f611b
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public Collection<Module<ExportFormat>> getExportFormats() {
result.add(new Module<ExportFormat>("AugmentLogosLinks", "Add values of Logos links to Extra Attributes of a Bible", AugmentLogosLinks.HELP_TEXT, AugmentLogosLinks.class));
result.add(new Module<ExportFormat>("LogosHTML", "HTML Export format for Logos Bible Software", LogosHTML.HELP_TEXT, LogosHTML.class));
result.add(new Module<ExportFormat>("LaridianPocketBibleExtendedInterlinear", "Export to Laridian Pocket Bible with Interlinear fields from Logos links", LaridianPocketBibleExtendedInterlinear.HELP_TEXT, LaridianPocketBibleExtendedInterlinear.class));
result.add(new Module<ExportFormat>("ReplaceStrongs", "Replace Strongs numbers by pattern or from other Logos links (e.g. GreekGK).", ReplaceStrongs.HELP_TEXT, ReplaceStrongs.class));
return result;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package biblemulticonverter.logos.format;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import biblemulticonverter.Main;
import biblemulticonverter.ModuleRegistry.Module;
import biblemulticonverter.data.Bible;
import biblemulticonverter.data.Book;
import biblemulticonverter.data.Chapter;
import biblemulticonverter.data.FormattedText;
import biblemulticonverter.data.FormattedText.Visitor;
import biblemulticonverter.data.Utils;
import biblemulticonverter.data.Verse;
import biblemulticonverter.data.Versification;
import biblemulticonverter.format.ExportFormat;

public class ReplaceStrongs implements ExportFormat {

public static final String[] HELP_TEXT = {
"Replace Strongs numbers by pattern or from other Logos links (e.g. GreekGK).",
"",
"Usage: ReplaceStrongs <pattern>=<replacement> [...] -- <ExportFormat> [<ExportArgs>...]",
"",
"Patterns can be either Strongs numbers or (full) Logos links, replacements are Strongs numbers.",
"",
"Placeholders in patterns are $ (prefix letter), # (number), ! (optional suffix letter).",
"For example, $#!=$#! will keep all Strongs numbers, while G#=Q# will change e.g. G123 to Q123."
};

@Override
public void doExport(Bible bible, String... exportArgs) throws Exception {
int formatArg = 0;
LogosLinksGenerator linksGenerator = new LogosLinksGenerator();
List<PatternRule> rules = new ArrayList<>();
while (!exportArgs[formatArg].equals("--")) {
rules.add(new PatternRule(exportArgs[formatArg]));
formatArg++;
}
formatArg++;

for (Book book : bible.getBooks()) {
int cnum = 0;
for (Chapter chapter : book.getChapters()) {
cnum++;
List<Verse> verses = chapter.getVerses();
for (int i = 0; i < verses.size(); i++) {
Verse v1 = verses.get(i);
Verse v2 = new Verse(v1.getNumber());
v1.accept(new ReplaceStrongsVisitor(v2.getAppendVisitor(), new Versification.Reference(book.getId(), cnum, v1.getNumber()), linksGenerator, rules));
v2.finished();
verses.set(i, v2);
}
}
}

Module<ExportFormat> exportModule = Main.exportFormats.get(exportArgs[formatArg]);
ExportFormat exportFormat = exportModule.getImplementationClass().newInstance();
exportFormat.doExport(bible, Arrays.copyOfRange(exportArgs, formatArg + 1, exportArgs.length));
}

private static String[] build_FullStrongs(Versification.Reference reference, char[] strongsPrefixes, int[] strongs) {
if (strongs == null)
return null;
if (strongsPrefixes == null) {
strongsPrefixes = new char[strongs.length];
Arrays.fill(strongsPrefixes, reference.getBook().isNT() ? 'G' : 'H');
}
String[] result = new String[strongs.length];
for (int i = 0; i < strongs.length; i++) {
result[i] = strongsPrefixes[i] + "" + strongs[i];
}
return result;
}

private static class PatternRule {
final Pattern pattern;
final String replacement;

public PatternRule(String rule) {
String[] parts = rule.split("=");
if (parts.length != 2)
throw new RuntimeException("Invalid pattern rule: " + rule);
StringBuilder ptn = new StringBuilder(), rpl = new StringBuilder();
for (String placeholder : Arrays.asList("$", "#", "!")) {
if (parts[1].contains(placeholder) && !parts[0].contains(placeholder)) {
throw new RuntimeException("Invalid pattern rule - cannot replace " + placeholder + " as not contained in pattern: " + rule);
}
}
pattern = Pattern.compile("^" + replacePlaceholders(parts[0], Pattern::quote, "(?<P>[A-Z])", "(?<N>[0-9]+)", "(?<S>[a-zA-Z]?)") + "$");
replacement = replacePlaceholders(parts[1], Matcher::quoteReplacement, "${P}", "${N}", "${S}");
}

private static String replacePlaceholders(String pattern, Function<String, String> quoteFunction, String replacement4Prefix, String replacement4Number, String replacement4Suffix) {
StringBuilder result = new StringBuilder();
Matcher m = Utils.compilePattern("[$#!]").matcher(pattern);
int lastPos = 0;
while (m.find()) {
result.append(quoteFunction.apply(pattern.substring(lastPos, m.start())));
switch (m.group().charAt(0)) {
case '$':
result.append(replacement4Prefix);
break;
case '#':
result.append(replacement4Number);
break;
case '!':
result.append(replacement4Suffix);
break;
default:
throw new IllegalStateException(m.group());
}
lastPos = m.end();
}
result.append(quoteFunction.apply(pattern.substring(lastPos)));
return result.toString();
}
}

private static class ReplaceStrongsVisitor extends FormattedText.VisitorAdapter<RuntimeException> {

private final Versification.Reference reference;
private final LogosLinksGenerator linksGenerator;
private final List<PatternRule> rules;

private ReplaceStrongsVisitor(Visitor<RuntimeException> next, Versification.Reference reference, LogosLinksGenerator linksGenerator, List<PatternRule> rules) throws RuntimeException {
super(next);
this.reference = reference;
this.linksGenerator = linksGenerator;
this.rules = rules;
}

@Override
protected Visitor<RuntimeException> wrapChildVisitor(Visitor<RuntimeException> childVisitor) throws RuntimeException {
return new ReplaceStrongsVisitor(childVisitor, reference, linksGenerator, rules);
}

@Override
public Visitor<RuntimeException> visitGrammarInformation(char[] strongsPrefixes, int[] strongs, String[] rmac, int[] sourceIndices) throws RuntimeException {
if (strongs != null) {
List<String> newStrongs = new ArrayList<>();
char[] oneStrongsPrefix = new char[1];
int[] oneStrongs = new int[1];
for (int i = 0; i < strongs.length; i++) {
oneStrongs[0] = strongs[i];
oneStrongsPrefix[0] = strongsPrefixes == null ? '?' : strongsPrefixes[i];
List<String> links = linksGenerator.generateLinks(reference.getBook().isNT(), reference, strongsPrefixes == null ? null : oneStrongsPrefix, oneStrongs, rmac, sourceIndices);
links.add(Utils.formatStrongs(reference.getBook().isNT(), strongsPrefixes == null ? null : strongsPrefixes[i], strongs[i]));
outer: for (PatternRule rule : rules) {
for (String link : links) {
Matcher m = rule.pattern.matcher(link);
if (m.matches()) {
m.reset();
newStrongs.add(m.replaceFirst(rule.replacement));
break outer;
}
}
}
}

if (newStrongs.isEmpty()) {
strongs = null;
strongsPrefixes = null;
} else {
strongs = new int[newStrongs.size()];
strongsPrefixes = new char[newStrongs.size()];
for (int i = 0; i < strongs.length; i++) {
strongs[i] = Utils.parseStrongs(newStrongs.get(i), '\0', oneStrongsPrefix);
strongsPrefixes[i] = oneStrongsPrefix[0];
}
}
}
if (strongs == null && rmac == null && sourceIndices == null) {
return this;
}
return wrapChildVisitor(getVisitor().visitGrammarInformation(strongsPrefixes, strongs, rmac, sourceIndices));
}
}
}

0 comments on commit 96f611b

Please sign in to comment.