/**
* This file is part of Archiv-Editor.
*
* The software Archiv-Editor serves as a client user interface for working with
* the Person Data Repository. See: pdr.bbaw.de
*
* The software Archiv-Editor was developed at the Berlin-Brandenburg Academy
* of Sciences and Humanities, Jägerstr. 22/23, D-10117 Berlin.
* www.bbaw.de
*
* Copyright (C) 2010-2013 Berlin-Brandenburg Academy
* of Sciences and Humanities
*
* The software Archiv-Editor was developed by @author: Christoph Plutte.
*
* Archiv-Editor is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Archiv-Editor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Archiv-Editor.
* If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package org.bbaw.pdr.dates;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* DatesUtils enthält die statischen Methoden zur Datumserkennung.
* D.h. zur Kodierung des Originaltextes,
* zur Erkennung von Datumsangaben aus dem kodierten Text,
* zur Formatierung der erkannten Angaben ins ISO-Format.
* @author Martin Fechner
*/
class DatesTools
{
// METHODEN
/**
* Schreibt das Kodesymbol in den kodierten Text bei i, wenn das Muster
* und der Originaltext übereinstimmen.
* Bsp.: "\\d" durch "sD1_"
* @param result Das zu bearbeitende DatesResult-Objekt.
* @param i Position des Elements.
* @param must Das Muster als regulärer Ausdruck.
* @param symb Das Kodesymbol.
*/
static void code(DatesResult result, int i, DatesConstant dconst){
String regex = dconst.r();
String symb = dconst.s();
if (result.original(i).matches(regex))
result.writeCodedText(i, symb);
}
/**
* Sucht das Muster im Kode.
* @param result Das zu bearbeitende DatesResult-Objekt.
* @param p Das im kodierten Text zu suchende Pattern.
* @return Gibt an, ob das Muster gefunden wurde.
*/
static boolean findPattern(DatesResult result, DatesSymbol dsymb){
boolean identified = false;
Pattern p = dsymb.p();
Matcher m = p.matcher(result.coded());
while (m.find()){
int start = m.start()/4;
int length = (m.end()/4-m.start()/4);
if (result.identifiedLength(start)<length){
identified = true;
}
}
return identified;
}
/**
* Sucht das Muster im Kode, und schreibt Länge und Bezeichner
* in ErkannterText.
* @param result Das zu bearbeitende DatesResult-Objekt.
* @param p Das im kodierten Text zu suchende Pattern.
* @param bez Das Array enthält die Bezeichner.
* @return Gibt an, ob das Muster gefunden und markiert wurde.
*/
static boolean identifyDate(DatesResult result, DatesSymbol dsymb){
boolean identified = false;
Pattern p = dsymb.p();
DatesSymbol.Label[] bez = dsymb.l();
Matcher m = p.matcher(result.coded());
while (m.find()){
int start = m.start()/4;
int length = (m.end()/4-m.start()/4);
if (result.identifiedLength(start)<length){
identified = true;
for (int i=start; i<start+length; i++){
result.writeIdentifiedLength(i, length);
result.writeIdentifiedText(i, bez[i-start]);
}
}
}
return identified;
}
/**
* Sucht das Muster vor schon erkannten Angaben und kombiniert
* Muster und Angabe zu einem langen Datum.
* @param result Das zu bearbeitende DatesResult-Objekt.
* @param p Das im kodierten Text zu suchende Pattern.
* @param bez Das Array enthält die Bezeichner.
* @return Gibt an, ob das Muster gefunden und markiert wurde.
*/
static boolean identifyPrePhrase(DatesResult result, DatesSymbol dsymb){
boolean identified = false;
Pattern p = dsymb.p();
DatesSymbol.Label[] bez = dsymb.l();
Matcher m = p.matcher(result.coded());
while (m.find()){
int start = m.start()/4;
int length = (m.end()/4-m.start()/4);
if (result.identifiedLength(start)==0 &&
result.identifiedLength(start+length-1)==0 &&
result.identifiedLength(start+length)!=0){
identified = true;
int newlength = length + result.identifiedLength(start+length);
for (int i=start; i<start+newlength; i++){
result.writeIdentifiedLength(i, newlength);
if (i< start+length)
result.writeIdentifiedText(i, bez[i-start]);
}
}
}
return identified;
}
/**
* Sucht das Muster zwischen zwei erkannten Angaben und kombiniert
* die drei zu einer langen Angabe.
* @param result Das zu bearbeitende DatesResult-Objekt.
* @param p Das im kodierten Text zu suchende Pattern.
* @param bez Das Array enthält die Bezeichner.
* @return Gibt an, ob das Muster gefunden und markiert wurde.
*/
static boolean identifyConnection(DatesResult result, DatesSymbol dsymb){
boolean identified = false;
Pattern p = dsymb.p();
DatesSymbol.Label[] label = dsymb.l();
Matcher m = p.matcher(result.coded());
while (m.find()){
int start = m.start()/4;
int length = (m.end()/4-m.start()/4);
if (result.identifiedLength(start-1)!=0 && result.identifiedLength(start)==0 &&
result.identifiedLength(start+length)!=0){
identified = true;
int newLength = length + result.identifiedLength(start-1) +
result.identifiedLength(start+length);
int newStart = start - result.identifiedLength(start-1);
for (int i=newStart; i<newStart+newLength; i++){
result.writeIdentifiedLength(i, newLength);
if (i>=start && i<start+length)
result.writeIdentifiedText(i, label[i-start]);
if (i>=start+length){
// Bezeichner der zweiten Datumsangabe
// ändern: Jahr1 zu Jahr2
DatesSymbol.Label newLabel;
switch (result.identified(i)){
case YEAR1:
newLabel = DatesSymbol.Label.YEAR2;
break;
case MONTH1:
newLabel = DatesSymbol.Label.MONTH2;
break;
case DAY1:
newLabel = DatesSymbol.Label.DAY2;
break;
case APPROXIMATION1:
newLabel = DatesSymbol.Label.APPROXIMATION2;
break;
case LIMIT1:
newLabel = DatesSymbol.Label.LIMIT2;
break;
default:
newLabel = DatesSymbol.Label.EMPTY;
break;
}
result.writeIdentifiedText(i, newLabel);
}
}
}
}
return identified;
}
/**
* Sucht das Muster für eine unvollständige Datumsangabe vor
* erkannten Angaben und kombiniert beide. Bsp.: "3.-" vor "13.10.1990"
* @param result Das zu bearbeitende DatesResult-Objekt.
* @param p Das im kodierten Text zu suchende Pattern.
* @param bez Das Array enthält die Bezeichner.
* @return Gibt an, ob das Muster gefunden und markiert wurde.
*/
static boolean identifyPreDate(DatesResult result, DatesSymbol dsymb){
boolean identified = false;
Pattern p = dsymb.p();
DatesSymbol.Label[] label = dsymb.l();
Matcher m = p.matcher(result.coded());
while (m.find()){
int start = m.start()/4;
int length = (m.end()/4-m.start()/4);
if (result.identifiedLength(start)==0 &&
result.identifiedLength(start+length)!=0){
identified = true;
int newLength = length + result.identifiedLength(start+length);
for (int i=start; i<start+newLength; i++){
result.writeIdentifiedLength(i, newLength);
if (i< start + length)
result.writeIdentifiedText(i, label[i-start]);
if (i>= start + length){
// Ändert die Bezeichner der zweiten Datumsangabe
DatesSymbol.Label newLabel;
switch (result.identified(i)){
case YEAR1:
newLabel = DatesSymbol.Label.YEAR2;
break;
case MONTH1:
newLabel = DatesSymbol.Label.MONTH2;
break;
case DAY1:
newLabel = DatesSymbol.Label.DAY2;
break;
case APPROXIMATION1:
newLabel = DatesSymbol.Label.APPROXIMATION2;
break;
case LIMIT1:
newLabel = DatesSymbol.Label.LIMIT2;
break;
default:
newLabel = DatesSymbol.Label.EMPTY;
break;
}
result.writeIdentifiedText(i, newLabel);
}
}
}
}
return identified;
}
/**
* Sucht das Muster für eine unvollständige Datumsangabe nach
* erkannten Angaben und kombiniert beide. Bsp.: "1990" und "-99"
* @param result Das zu bearbeitende DatesResult-Objekt.
* @param p Das im kodierten Text zu suchende Pattern.
* @param bez Das Array enthält die Bezeichner.
* @return Gibt an, ob das Muster gefunden und markiert wurde.
*/
static boolean identifyAfterDate(DatesResult result, DatesSymbol dsymb){
boolean identified = false;
Pattern p = dsymb.p();
DatesSymbol.Label[] label = dsymb.l();
Matcher m = p.matcher(result.coded());
while (m.find()){
int start = m.start()/4;
int length = (m.end()/4-m.start()/4);
if (result.identifiedLength(start-1)!=0
&& result.identified(start-1).equals(DatesSymbol.Label.YEAR1)
&& result.identifiedLength(start)==0){
identified = true;
int newLength = result.identifiedLength(start-1) + length;
int newStart = start - result.identifiedLength(start-1);
for (int i=newStart; i<newStart+newLength; i++){
result.writeIdentifiedLength(i, newLength);
if (i>=start){
result.writeIdentifiedText(i, label[i-start]);
}
}
}
}
return identified;
}
/**
* Berechnet das Osterdatum in einem bestimmten Jahr.
* @param year Das Jahr, in dem Ostern berechnet werden soll.
* @return Der Tag, an dem Ostersonntag liegt, vom 1. März ausgerechnet.
*/
static int easterDate(String year)
{
int X = Integer.parseInt(year);
int K,M,S,A,D,R,OG,SZ,OE,OS;
K = X/100;
M = 15 + ((3*K+3)/4) - ((8*K+13)/25);
S = 2 - ((3*K+3)/4);
A = X%19;
D = (19*A+M)%30;
R = (D/29) + ((D/28) - (D/ 29)) * (A/11);
OG = 21 + D - R;
SZ = 7 - (X+(X/4)+S)%7;
OE = 7 - (OG-SZ)%7;
OS = OG+OE;
return OS;
}
/**
* Berechnet, ob es sich bei dem angegeben Jahr um ein Schaltjahr handelt.
*/
static boolean isLeapYear(String year)
{
boolean leapYear = false;
int y = Integer.parseInt(year);
if ( ( (y%4)==0 && (y%100)!=0 ) ||
( (y%4)==0 && (y%400)==0 ) )
leapYear = true;
return leapYear;
}
}