(no commit message)
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / strategy / parser / NonViralNameParserImpl.java
1 /**
2 *
3 */
4 package eu.etaxonomy.cdm.strategy.parser;
5
6 import java.util.regex.Matcher;
7 import java.util.regex.Pattern;
8
9 import org.apache.log4j.Logger;
10 import org.joda.time.DateTimeFieldType;
11 import org.joda.time.Partial;
12
13 import eu.etaxonomy.cdm.common.CdmUtils;
14 import eu.etaxonomy.cdm.model.agent.Person;
15 import eu.etaxonomy.cdm.model.agent.Team;
16 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
17 import eu.etaxonomy.cdm.model.common.CdmBase;
18 import eu.etaxonomy.cdm.model.common.IParsable;
19 import eu.etaxonomy.cdm.model.common.TimePeriod;
20 import eu.etaxonomy.cdm.model.name.BacterialName;
21 import eu.etaxonomy.cdm.model.name.BotanicalName;
22 import eu.etaxonomy.cdm.model.name.CultivarPlantName;
23 import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
24 import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
25 import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
26 import eu.etaxonomy.cdm.model.name.NonViralName;
27 import eu.etaxonomy.cdm.model.name.Rank;
28 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
29 import eu.etaxonomy.cdm.model.name.ZoologicalName;
30 import eu.etaxonomy.cdm.model.reference.IGeneric;
31 import eu.etaxonomy.cdm.model.reference.IArticle;
32 import eu.etaxonomy.cdm.model.reference.IBook;
33 import eu.etaxonomy.cdm.model.reference.IBookSection;
34 import eu.etaxonomy.cdm.model.reference.IJournal;
35 import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
36 import eu.etaxonomy.cdm.model.reference.IReferenceBase;
37 import eu.etaxonomy.cdm.model.reference.IVolumeReference;
38 import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
39 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
40 import eu.etaxonomy.cdm.model.reference.ReferenceType;
41 import eu.etaxonomy.cdm.strategy.exceptions.StringNotParsableException;
42 import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
43
44
45 /**
46 * @author a.mueller
47 *
48 */
49 public class NonViralNameParserImpl extends NonViralNameParserImplRegExBase implements INonViralNameParser<NonViralName> {
50 private static final Logger logger = Logger.getLogger(NonViralNameParserImpl.class);
51
52 // good intro: http://java.sun.com/docs/books/tutorial/essential/regex/index.html
53
54 final static boolean MAKE_EMPTY = true;
55 final static boolean MAKE_NOT_EMPTY = false;
56 private ReferenceFactory refFactory = ReferenceFactory.newInstance();
57
58
59 public static NonViralNameParserImpl NewInstance(){
60 return new NonViralNameParserImpl();
61 }
62
63 /* (non-Javadoc)
64 * @see eu.etaxonomy.cdm.strategy.ITaxonNameParser#parseSubGenericSimpleName(java.lang.String)
65 */
66 public NonViralName parseSimpleName(String simpleName){
67 return parseSimpleName(simpleName, null, null);
68 }
69
70
71 /* (non-Javadoc)
72 * @see eu.etaxonomy.cdm.strategy.parser.INonViralNameParser#parseSimpleName(java.lang.String, eu.etaxonomy.cdm.model.name.NomenclaturalCode, eu.etaxonomy.cdm.model.name.Rank)
73 */
74 public NonViralName parseSimpleName(String simpleName, NomenclaturalCode code, Rank rank){
75 //"parseSimpleName() not yet implemented. Uses parseFullName() instead");
76 return parseFullName(simpleName, code, rank);
77 }
78
79 public void parseSimpleName(NonViralName nameToBeFilled, String simpleNameString, Rank rank, boolean makeEmpty){
80 //"parseSimpleName() not yet implemented. Uses parseFullName() instead");
81 parseFullName(nameToBeFilled, simpleNameString, rank, makeEmpty);
82 }
83
84
85 public NonViralName getNonViralNameInstance(String fullString, NomenclaturalCode code){
86 return getNonViralNameInstance(fullString, code, null);
87 }
88
89 public NonViralName getNonViralNameInstance(String fullString, NomenclaturalCode code, Rank rank){
90 NonViralName result = null;
91 if(code ==null) {
92 boolean isBotanicalName = anyBotanicFullNamePattern.matcher(fullString).find();
93 boolean isZoologicalName = anyZooFullNamePattern.matcher(fullString).find();;
94 boolean isBacteriologicalName = false;
95 boolean isCultivatedPlantName = false;
96 if ( (isBotanicalName || isCultivatedPlantName) && ! isZoologicalName && !isBacteriologicalName){
97 if (isBotanicalName){
98 result = BotanicalName.NewInstance(rank);
99 }else{
100 result = CultivarPlantName.NewInstance(rank);
101 }
102 }else if ( isZoologicalName /*&& ! isBotanicalName*/ && !isBacteriologicalName && !isCultivatedPlantName){
103 result = ZoologicalName.NewInstance(rank);
104 }else if ( isZoologicalName && ! isBotanicalName && !isBacteriologicalName && !isCultivatedPlantName){
105 result = BacterialName.NewInstance(rank);
106 }else {
107 result = NonViralName.NewInstance(rank);
108 }
109 } else {
110 switch (code) {
111 case ICBN:
112 result = BotanicalName.NewInstance(rank);
113 break;
114 case ICZN:
115 result = ZoologicalName.NewInstance(rank);
116 break;
117 case ICNCP:
118 logger.warn("ICNCP parsing not yet implemented");
119 result = CultivarPlantName.NewInstance(rank);
120 break;
121 case ICNB:
122 logger.warn("ICNB not yet implemented");
123 result = BacterialName.NewInstance(rank);
124 break;
125 case ICVCN:
126 logger.error("Viral name is not a NonViralName !!");
127 break;
128 default:
129 // FIXME Unreachable code
130 logger.error("Unknown Nomenclatural Code !!");
131 }
132 }
133 return result;
134 }
135
136
137 /* (non-Javadoc)
138 * @see eu.etaxonomy.cdm.strategy.parser.INonViralNameParser#parseFullReference(java.lang.String)
139 */
140 public NonViralName parseReferencedName(String fullReferenceString) {
141 return parseReferencedName(fullReferenceString, null, null);
142 }
143
144 /* (non-Javadoc)
145 * @see eu.etaxonomy.cdm.strategy.ITaxonNameParser#parseFullReference(java.lang.String, eu.etaxonomy.cdm.model.name.Rank)
146 */
147 public NonViralName parseReferencedName(String fullReferenceString, NomenclaturalCode nomCode, Rank rank) {
148 if (fullReferenceString == null){
149 return null;
150 }else{
151 NonViralName result = getNonViralNameInstance(fullReferenceString, nomCode, rank);
152 parseReferencedName(result, fullReferenceString, rank, MAKE_EMPTY);
153 return result;
154 }
155 }
156
157 private String standardize(NonViralName nameToBeFilled, String fullReferenceString, boolean makeEmpty){
158 //Check null and standardize
159 if (fullReferenceString == null){
160 //return null;
161 return null;
162 }
163 if (makeEmpty){
164 makeEmpty(nameToBeFilled);
165 }
166 fullReferenceString = fullReferenceString.replaceAll(oWs , " ");
167 fullReferenceString = fullReferenceString.trim();
168 if ("".equals(fullReferenceString)){
169 fullReferenceString = null;
170 }
171 return fullReferenceString;
172 }
173
174 /**
175 * Returns the regEx to be used for the full-name depending on the code
176 * @param nameToBeFilled
177 * @return
178 */
179 private String getLocalFullName(NonViralName nameToBeFilled){
180 if (nameToBeFilled instanceof ZoologicalName){
181 return anyZooFullName;
182 }else if (nameToBeFilled instanceof BotanicalName) {
183 return anyBotanicFullName;
184 }else if (nameToBeFilled instanceof NonViralName) {
185 return anyBotanicFullName; //TODO ?
186 }else{
187 logger.warn("nameToBeFilled class not supported ("+nameToBeFilled.getClass()+")");
188 return null;
189 }
190 }
191
192 /**
193 * Returns the regEx to be used for the fsimple-name depending on the code
194 * @param nameToBeFilled
195 * @return
196 */
197 private String getLocalSimpleName(NonViralName nameToBeFilled){
198 if (nameToBeFilled instanceof ZoologicalName){
199 return anyZooName;
200 }else if (nameToBeFilled instanceof NonViralName){
201 return anyZooName; //TODO ?
202 }else if (nameToBeFilled instanceof BotanicalName) {
203 return anyBotanicName;
204 }else{
205 logger.warn("nameToBeFilled class not supported ("+nameToBeFilled.getClass()+")");
206 return null;
207 }
208 }
209
210 private Matcher getMatcher(String regEx, String matchString){
211 Pattern pattern = Pattern.compile(regEx);
212 Matcher matcher = pattern.matcher(matchString);
213 return matcher;
214 }
215
216 /* (non-Javadoc)
217 * @see eu.etaxonomy.cdm.strategy.ITaxonNameParser#parseFullReference(eu.etaxonomy.cdm.model.name.BotanicalName, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, boolean)
218 */
219 public void parseReferencedName(NonViralName nameToBeFilled, String fullReferenceString, Rank rank, boolean makeEmpty) {
220 //standardize
221 fullReferenceString = standardize(nameToBeFilled, fullReferenceString, makeEmpty);
222 if (fullReferenceString == null){
223 return;
224 }
225 // happens already in standardize(...)
226 // makeProblemEmpty(nameToBeFilled);
227
228 //make nomenclatural status and replace it by empty string
229 fullReferenceString = parseNomStatus(fullReferenceString, nameToBeFilled);
230 nameToBeFilled.setProblemEnds(fullReferenceString.length());
231
232 //get full name reg
233 String localFullName = getLocalFullName(nameToBeFilled);
234 //get full name reg
235 String localSimpleName = getLocalSimpleName(nameToBeFilled);
236
237 //separate name and reference part
238 String nameAndRefSeparator = "(^" + localFullName + ")("+ referenceSeperator + ")";
239 Matcher nameAndRefSeparatorMatcher = getMatcher (nameAndRefSeparator, fullReferenceString);
240
241 Matcher onlyNameMatcher = getMatcher (localFullName, fullReferenceString);
242 Matcher onlySimpleNameMatcher = getMatcher (localSimpleName, fullReferenceString);
243
244 if (nameAndRefSeparatorMatcher.find()){
245 makeNameWithReference(nameToBeFilled, fullReferenceString, nameAndRefSeparatorMatcher, rank, makeEmpty);
246 }else if (onlyNameMatcher.matches()){
247 makeEmpty = false;
248 parseFullName(nameToBeFilled, fullReferenceString, rank, makeEmpty);
249 }else if (onlySimpleNameMatcher.matches()){
250 makeEmpty = false;
251 parseFullName(nameToBeFilled, fullReferenceString, rank, makeEmpty); //simpleName not yet implemented
252 }else{
253 makeNoFullRefMatch(nameToBeFilled, fullReferenceString, rank);
254 }
255 //problem handling. Start and end solved in subroutines
256 if (! nameToBeFilled.hasProblem()){
257 makeProblemEmpty(nameToBeFilled);
258 }
259 }
260
261 private void makeProblemEmpty(IParsable parsable){
262 boolean hasCheckRank = parsable.hasProblem(ParserProblem.CheckRank);
263 parsable.setParsingProblem(0);
264 if (hasCheckRank){
265 parsable.addParsingProblem(ParserProblem.CheckRank);
266 }
267 parsable.setProblemStarts(-1);
268 parsable.setProblemEnds(-1);
269 }
270
271 private void makeNoFullRefMatch(NonViralName nameToBeFilled, String fullReferenceString, Rank rank){
272 //try to parse first part as name, but keep in mind full string is not parsable
273 int start = 0;
274
275 String localFullName = getLocalFullName(nameToBeFilled);
276 Matcher fullNameMatcher = getMatcher (pStart + localFullName, fullReferenceString);
277 if (fullNameMatcher.find()){
278 String fullNameString = fullNameMatcher.group(0);
279 nameToBeFilled.setProtectedNameCache(false);
280 parseFullName(nameToBeFilled, fullNameString, rank, false);
281 String sure = nameToBeFilled.getNameCache();
282 start = sure.length();
283 }
284
285 // String localSimpleName = getLocalSimpleName(nameToBeFilled);
286 // Matcher simpleNameMatcher = getMatcher (start + localSimpleName, fullReferenceString);
287 // if (simpleNameMatcher.find()){
288 // String simpleNameString = simpleNameMatcher.group(0);
289 // parseFullName(nameToBeFilled, simpleNameString, rank, false);
290 // start = simpleNameString.length();
291 // }
292
293 //don't parse if name can't be separated
294 nameToBeFilled.addParsingProblem(ParserProblem.NameReferenceSeparation);
295 nameToBeFilled.setTitleCache(fullReferenceString);
296 nameToBeFilled.setFullTitleCache(fullReferenceString);
297 // FIXME Quick fix, otherwise search would not deliver results for unparsable names
298 nameToBeFilled.setNameCache(fullReferenceString);
299 // END
300 nameToBeFilled.setProblemStarts(start);
301 nameToBeFilled.setProblemEnds(fullReferenceString.length());
302 logger.info("no applicable parsing rule could be found for \"" + fullReferenceString + "\"");
303 }
304
305 private void makeNameWithReference(NonViralName nameToBeFilled,
306 String fullReferenceString,
307 Matcher nameAndRefSeparatorMatcher,
308 Rank rank,
309 boolean makeEmpty){
310
311 String nameAndSeparator = nameAndRefSeparatorMatcher.group(0);
312 String name = nameAndRefSeparatorMatcher.group(1);
313 String referenceString = fullReferenceString.substring(nameAndRefSeparatorMatcher.end());
314
315 // is reference an in ref?
316 String separator = nameAndSeparator.substring(name.length());
317 boolean isInReference = separator.matches(inReferenceSeparator);
318
319 //parse subparts
320
321 int oldProblemEnds = nameToBeFilled.getProblemEnds();
322 parseFullName(nameToBeFilled, name, rank, makeEmpty);
323 nameToBeFilled.setProblemEnds(oldProblemEnds);
324
325 //zoological new combinations should not have a nom. reference to be parsed
326 if (nameToBeFilled.isInstanceOf(ZoologicalName.class)){
327 ZoologicalName zooName = CdmBase.deproxy(nameToBeFilled, ZoologicalName.class);
328 //is name new combination?
329 if (zooName.getBasionymAuthorTeam() != null || zooName.getOriginalPublicationYear() != null){
330 ParserProblem parserProblem = ParserProblem.NewCombinationHasPublication;
331 zooName.addParsingProblem(parserProblem);
332 nameToBeFilled.setProblemStarts((nameToBeFilled.getProblemStarts()> -1) ? nameToBeFilled.getProblemStarts(): name.length());
333 nameToBeFilled.setProblemEnds(Math.max(fullReferenceString.length(), nameToBeFilled.getProblemEnds()));
334 }
335 }
336
337 parseReference(nameToBeFilled, referenceString, isInReference);
338 INomenclaturalReference ref = (INomenclaturalReference)nameToBeFilled.getNomenclaturalReference();
339
340 //problem start
341 int start = nameToBeFilled.getProblemStarts();
342 int nameLength = name.length();
343 int nameAndSeparatorLength = nameAndSeparator.length();
344 int fullRefLength = nameToBeFilled.getFullTitleCache().length();
345
346 if (nameToBeFilled.isProtectedTitleCache() || nameToBeFilled.getParsingProblems().contains(ParserProblem.CheckRank)){
347 start = Math.max(0, start);
348 }else{
349 if (ref != null && ref.getParsingProblem()!=0){
350 start = Math.max(nameAndSeparatorLength, start);
351 //TODO search within ref
352 }
353 }
354
355 //end
356 int end = nameToBeFilled.getProblemEnds();
357
358 if (ref != null && ref.getParsingProblem()!=0){
359 end = Math.min(nameAndSeparatorLength + ref.getProblemEnds(), end);
360 }else{
361 if (nameToBeFilled.isProtectedTitleCache() ){
362 end = Math.min(end, nameAndSeparatorLength);
363 //TODO search within name
364 }
365 }
366 nameToBeFilled.setProblemStarts(start);
367 nameToBeFilled.setProblemEnds(end);
368
369 //delegate has problem to name
370 if (ref != null && ref.getParsingProblem()!=0){
371 nameToBeFilled.addParsingProblems(ref.getParsingProblem());
372 }
373
374 ReferenceBase nomRef;
375 if ( (nomRef = (ReferenceBase)nameToBeFilled.getNomenclaturalReference()) != null ){
376 nomRef.setAuthorTeam((TeamOrPersonBase)nameToBeFilled.getCombinationAuthorTeam());
377 }
378 }
379
380 //TODO make it an Array of status
381 /**
382 * Extracts a {@link NomenclaturalStatus} from the reference String and adds it to the @link {@link TaxonNameBase}.
383 * The nomenclatural status part ist deleted from the reference String.
384 * @return String the new (shortend) reference String
385 */
386 private String parseNomStatus(String fullString, NonViralName nameToBeFilled) {
387 String statusString;
388 Pattern hasStatusPattern = Pattern.compile("(" + pNomStatusPhrase + ")");
389 Matcher hasStatusMatcher = hasStatusPattern.matcher(fullString);
390
391 if (hasStatusMatcher.find()) {
392 String statusPhrase = hasStatusMatcher.group(0);
393
394 Pattern statusPattern = Pattern.compile(pNomStatus);
395 Matcher statusMatcher = statusPattern.matcher(statusPhrase);
396 statusMatcher.find();
397 statusString = statusMatcher.group(0);
398 try {
399 NomenclaturalStatusType nomStatusType = NomenclaturalStatusType.getNomenclaturalStatusTypeByAbbreviation(statusString);
400 NomenclaturalStatus nomStatus = NomenclaturalStatus.NewInstance(nomStatusType);
401 nameToBeFilled.addStatus(nomStatus);
402
403 fullString = fullString.replace(statusPhrase, "");
404 } catch (UnknownCdmTypeException e) {
405 //Do nothing
406 }
407 }
408 return fullString;
409 }
410
411
412 private void parseReference(NonViralName nameToBeFilled, String strReference, boolean isInReference){
413
414 INomenclaturalReference ref;
415 String originalStrReference = strReference;
416
417 //End (just delete end (e.g. '.', may be ambigous for yearPhrase, but no real information gets lost
418 Matcher endMatcher = getMatcher(referenceEnd + end, strReference);
419 if (endMatcher.find()){
420 String endPart = endMatcher.group(0);
421 strReference = strReference.substring(0, strReference.length() - endPart.length());
422 }
423
424 // String pDetailYear = ".*" + detailSeparator + detail + fWs + yearSeperator + fWs + yearPhrase + fWs + end;
425 // Matcher detailYearMatcher = getMatcher(pDetailYear, strReference);
426
427 String strReferenceWithYear = strReference;
428 //year
429 String yearPart = null;
430 String pYearPhrase = yearSeperator + fWs + yearPhrase + fWs + end;
431 Matcher yearPhraseMatcher = getMatcher(pYearPhrase, strReference);
432 if (yearPhraseMatcher.find()){
433 yearPart = yearPhraseMatcher.group(0);
434 strReference = strReference.substring(0, strReference.length() - yearPart.length());
435 yearPart = yearPart.replaceFirst(pStart + yearSeperator, "").trim();
436 }else{
437 if (nameToBeFilled.isInstanceOf(ZoologicalName.class)){
438 ZoologicalName zooName = CdmBase.deproxy(nameToBeFilled, ZoologicalName.class);
439 yearPart = String.valueOf(zooName.getPublicationYear());
440 //continue
441 }else{
442 ref = makeDetailYearUnparsable(nameToBeFilled,strReference);
443 ref.setDatePublished(TimePeriod.parseString(yearPart));
444 return;
445 }
446 }
447
448
449 //detail
450 String pDetailPhrase = detailSeparator + fWs + detail + fWs + end;
451 Matcher detailPhraseMatcher = getMatcher(pDetailPhrase, strReference);
452 if (detailPhraseMatcher.find()){
453 String detailPart = detailPhraseMatcher.group(0);
454 strReference = strReference.substring(0, strReference.length() - detailPart.length());
455 detailPart = detailPart.replaceFirst(pStart + detailSeparator, "").trim();
456 nameToBeFilled.setNomenclaturalMicroReference(detailPart);
457 }else{
458 makeDetailYearUnparsable(nameToBeFilled, strReferenceWithYear);
459 return;
460 }
461 //parse title and author
462 ref = parseReferenceTitle(strReference, yearPart, isInReference);
463 if (ref.hasProblem()){
464 ref.setTitleCache( (isInReference?"in ":"") + originalStrReference);
465 }
466 nameToBeFilled.setNomenclaturalReference((ReferenceBase)ref);
467 int end = Math.min(strReference.length(), ref.getProblemEnds());
468 ref.setProblemEnds(end);
469 }
470
471 /**
472 * @param nameToBeFilled
473 * @param strReference
474 * @return
475 */
476 private INomenclaturalReference makeDetailYearUnparsable(NonViralName nameToBeFilled, String strReference) {
477 INomenclaturalReference ref;
478 //ref = Generic.NewInstance();
479
480 ref = refFactory.newGeneric();
481 ref.setTitleCache(strReference);
482 ref.setProblemEnds(strReference.length());
483 ref.addParsingProblem(ParserProblem.CheckDetailOrYear);
484 nameToBeFilled.addParsingProblem(ParserProblem.CheckDetailOrYear);
485 nameToBeFilled.setNomenclaturalReference((ReferenceBase)ref);
486 return ref;
487 }
488
489 /**
490 * Parses the referenceTitlePart, including the author volume and edition.
491 * @param reference
492 * @param year
493 * @return
494 */
495 private INomenclaturalReference parseReferenceTitle(String strReference, String year, boolean isInReference){
496 IBook result = null;
497
498 Matcher refSineDetailMatcher = referenceSineDetailPattern.matcher(strReference);
499 if (! refSineDetailMatcher.matches()){
500 //TODO ?
501 }
502
503 Matcher articleMatcher = getMatcher(pArticleReference, strReference);
504
505 Matcher softArticleMatcher = getMatcher(pSoftArticleReference, strReference);
506 Matcher bookMatcher = getMatcher(pBookReference, strReference);
507 Matcher bookSectionMatcher = getMatcher(pBookSectionReference, strReference);
508
509
510 if(isInReference == false){
511 if (bookMatcher.matches() ){
512 result = parseBook(strReference);
513 }else{
514 logger.warn("Non-InRef must be book but does not match book");
515 result = refFactory.newBook();
516 makeUnparsableRefTitle(result, strReference);
517 }
518 }else{ //inRef
519 if (articleMatcher.matches()){
520 //article without separators like ","
521 result = parseArticle(strReference);
522 }else if (softArticleMatcher.matches()){
523 result = parseArticle(strReference);
524 }else if (bookSectionMatcher.matches()){
525 result = parseBookSection(strReference);
526 }else{
527 result = refFactory.newGeneric();
528 makeUnparsableRefTitle(result, "in " + strReference);
529 }
530 }
531 //make year
532 if (makeYear(result, year) == false){
533 //TODO
534 logger.warn("Year could not be parsed");
535 }
536 result.setProblemStarts(0);
537 result.setProblemEnds(strReference.length());
538 return result;
539 }
540
541 private void makeUnparsableRefTitle(INomenclaturalReference result, String reference){
542 result.setTitleCache(reference);
543 result.addParsingProblem(ParserProblem.UnparsableReferenceTitle);
544 }
545
546 /**
547 * Parses a single date string. If the string is not parsable a StringNotParsableException is thrown
548 * @param singleDateString
549 * @return
550 * @throws StringNotParsableException
551 */
552 private static Partial parseSingleDate(String singleDateString)
553 throws StringNotParsableException{
554 Partial dt = new Partial();
555 if (CdmUtils.isNumeric(singleDateString)){
556 try {
557 Integer year = Integer.valueOf(singleDateString.trim());
558 if (year > 1750 && year < 2050){
559 dt = dt.with(DateTimeFieldType.year(), year);
560 }else{
561 dt = null;
562 }
563 } catch (NumberFormatException e) {
564 logger.debug("Not a Integer format in getCalendar()");
565 throw new StringNotParsableException(singleDateString + "is not parsable as a single Date");
566 }
567 }
568 return dt;
569 }
570
571
572 /**
573 * Parses the publication date part.
574 * @param nomRef
575 * @param year
576 * @return If the string is not parsable <code>false</code>
577 * is returned. <code>True</code> otherwise
578 */
579 private boolean makeYear(INomenclaturalReference nomRef, String year){
580 boolean result = true;
581 if (year == null){
582 return false;
583 }
584 if ("".equals(year.trim())){
585 return true;
586 }
587 TimePeriod datePublished = TimePeriod.parseString(year);
588
589 if (nomRef.getType().equals(ReferenceType.BookSection)){
590 handleBookSectionYear((IBookSection)nomRef, datePublished);
591 }else if (nomRef instanceof ReferenceBase){
592 ((ReferenceBase)nomRef).setDatePublished(datePublished);
593 }else{
594 throw new ClassCastException("nom Ref is not of type ReferenceBase but " + (nomRef == null? "(null)" : nomRef.getClass()));
595 }
596 return result;
597 }
598
599 private String makeVolume(IVolumeReference nomRef, String strReference){
600 //volume
601 String volPart = null;
602 String pVolPhrase = volumeSeparator + volume + end;
603 Matcher volPhraseMatcher = getMatcher(pVolPhrase, strReference);
604 if (volPhraseMatcher.find()){
605 volPart = volPhraseMatcher.group(0);
606 strReference = strReference.substring(0, strReference.length() - volPart.length());
607 volPart = volPart.replaceFirst(pStart + volumeSeparator, "").trim();
608 nomRef.setVolume(volPart);
609 }
610 return strReference;
611 }
612
613 private String makeEdition(IBook book, String strReference){
614 //volume
615 String editionPart = null;
616 Matcher editionPhraseMatcher = getMatcher(pEditionPart, strReference);
617
618 Matcher editionVolumeMatcher = getMatcher(pEditionVolPart, strReference);
619 boolean isEditionAndVol = editionVolumeMatcher.find();
620
621 if (editionPhraseMatcher.find()){
622 editionPart = editionPhraseMatcher.group(0);
623 int pos = strReference.indexOf(editionPart);
624 int posEnd = pos + editionPart.length();
625 if (isEditionAndVol){
626 posEnd++; //delete also comma
627 }
628 strReference = strReference.substring(0, pos) + strReference.substring(posEnd);
629 editionPart = editionPart.replaceFirst(pStart + editionSeparator, "").trim();
630 book.setEdition(editionPart);
631 }
632 return strReference;
633 }
634
635 private IBook parseBook(String reference){
636 IBook result = refFactory.newBook();
637 reference = makeEdition(result, reference);
638 reference = makeVolume(result, reference);
639 result.setTitle(reference);
640 return result;
641 }
642
643
644 private ReferenceBase parseArticle(String reference){
645 //if (articlePatter)
646 //(type, author, title, volume, editor, series;
647 ReferenceBase result = refFactory.newArticle();
648 reference = makeVolume(result, reference);
649 ReferenceBase inJournal = refFactory.newJournal();
650 inJournal.setTitle(reference);
651 result.setInReference(inJournal);
652 return result;
653 }
654
655 private ReferenceBase parseBookSection(String reference){
656 ReferenceBase result = refFactory.newBookSection();
657 String[] parts = reference.split(referenceAuthorSeparator, 2);
658 if (parts.length != 2){
659 logger.warn("Unexpected number of parts");
660 result.setTitleCache(reference);
661 }else{
662 String authorString = parts[0];
663 String bookString = parts[1];
664
665 TeamOrPersonBase<?> authorTeam = author(authorString);
666 IBook inBook = parseBook(bookString);
667 inBook.setAuthorTeam(authorTeam);
668 result.setInBook(inBook);
669 }
670 return result;
671 }
672
673 /**
674 * If the publication date of a book section and it's inBook do differ this is usually
675 * caused by the fact that a book has been published during a period, because originally
676 * it consisted of several parts that only later where put together to one book.
677 * If so, the book section's publication date may be a point in time (year or month of year)
678 * whereas the books publication date may be a period of several years.
679 * Therefore a valid nomenclatural reference string should use the book sections
680 * publication date rather then the book's publication date.<BR>
681 * This method in general adds the publication date to the book section.
682 * An exception exists if the publication date is a period. Then the parser
683 * assumes that the nomenclatural reference string does not follow the above rule but
684 * the books publication date is set.
685 * @param bookSection
686 * @param datePublished
687 */
688 private void handleBookSectionYear(IBookSection bookSection, TimePeriod datePublished){
689 if (datePublished == null || datePublished.getStart() == null || bookSection == null){
690 return;
691 }
692 if (datePublished.isPeriod() && bookSection.getInBook() != null){
693 bookSection.getInBook().setDatePublished(datePublished);
694 }else{
695 bookSection.setDatePublished(datePublished);
696 }
697 }
698
699
700 /* (non-Javadoc)
701 * @see eu.etaxonomy.cdm.strategy.parser.INonViralNameParser#parseFullName(java.lang.String)
702 */
703 public NonViralName parseFullName(String fullNameString){
704 return parseFullName(fullNameString, null, null);
705 }
706
707
708 /* (non-Javadoc)
709 * @see eu.etaxonomy.cdm.strategy.ITaxonNameParser#parseFullName(java.lang.String, eu.etaxonomy.cdm.model.name.Rank)
710 */
711 public NonViralName parseFullName(String fullNameString, NomenclaturalCode nomCode, Rank rank) {
712
713 if (fullNameString == null){
714 return null;
715 }else{
716 NonViralName result = getNonViralNameInstance(fullNameString, nomCode, rank);
717 parseFullName(result, fullNameString, rank, false);
718 return result;
719 }
720 }
721
722
723 public void parseFullName(NonViralName nameToBeFilled, String fullNameString, Rank rank, boolean makeEmpty) {
724 //TODO prol. etc.
725 boolean hasCheckRankProblem = false; //was rank guessed in a previous parsing process?
726 if (nameToBeFilled == null){
727 logger.warn("name is null!");
728 }else{
729 hasCheckRankProblem = nameToBeFilled.hasProblem(ParserProblem.CheckRank);
730 nameToBeFilled.removeParsingProblem(ParserProblem.CheckRank);
731 }
732 String authorString = null;
733
734 if (fullNameString == null){
735 return;
736 }
737
738 if (makeEmpty){
739 makeEmpty(nameToBeFilled);
740 }
741 fullNameString.replaceAll(oWs , " ");
742 //TODO
743 // OLD: fullName = oWsRE.subst(fullName, " "); //substitute multiple whitespaces
744 fullNameString = fullNameString.trim();
745
746 String[] epi = pattern.split(fullNameString);
747 try {
748 //cultivars //TODO 2 implement cultivars
749 // if ( cultivarMarkerRE.match(fullName) ){ funktioniert noch nicht, da es z.B. auch Namen gibt, wie 't Hart
750 // result = parseCultivar(fullName);
751 // }
752 //hybrids //TODO 2 implement hybrids
753 //else
754 if (hybridPattern.matcher(fullNameString).matches() ){
755 nameToBeFilled = parseHybrid(fullNameString);
756 }
757 else if (genusOrSupraGenusPattern.matcher(fullNameString).matches()){
758 //supraGeneric
759 if (rank != null && ! hasCheckRankProblem && (rank.isSupraGeneric()|| rank.isGenus())){
760 nameToBeFilled.setRank(rank);
761 nameToBeFilled.setGenusOrUninomial(epi[0]);
762 }
763 //genus or guess rank
764 else {
765 rank = guessUninomialRank(nameToBeFilled, epi[0]);
766 nameToBeFilled.setRank(rank);
767 nameToBeFilled.setGenusOrUninomial(epi[0]);
768 nameToBeFilled.addParsingProblem(ParserProblem.CheckRank);
769 nameToBeFilled.setProblemStarts(0);
770 nameToBeFilled.setProblemEnds(epi[0].length());
771 }
772 authorString = fullNameString.substring(epi[0].length());
773 }
774 //infra genus
775 else if (infraGenusPattern.matcher(fullNameString).matches()){
776 nameToBeFilled.setRank(Rank.getRankByAbbreviation(epi[1]));
777 nameToBeFilled.setGenusOrUninomial(epi[0]);
778 nameToBeFilled.setInfraGenericEpithet(epi[2]);
779 authorString = fullNameString.substring(epi[0].length() + 1 + epi[1].length()+ 1 + epi[2].length());
780 }
781 //aggr. or group
782 else if (aggrOrGroupPattern.matcher(fullNameString).matches()){
783 nameToBeFilled.setRank(Rank.getRankByAbbreviation(epi[2]));
784 nameToBeFilled.setGenusOrUninomial(epi[0]);
785 nameToBeFilled.setSpecificEpithet(epi[1]);
786 }
787 //species
788 else if (speciesPattern.matcher(fullNameString).matches()){
789 nameToBeFilled.setRank(Rank.SPECIES());
790 nameToBeFilled.setGenusOrUninomial(epi[0]);
791 nameToBeFilled.setSpecificEpithet(epi[1]);
792 authorString = fullNameString.substring(epi[0].length() + 1 + epi[1].length());
793 }
794 //autonym
795 else if (autonymPattern.matcher(fullNameString).matches()){
796 nameToBeFilled.setRank(Rank.getRankByAbbreviation(epi[epi.length - 2]));
797 nameToBeFilled.setGenusOrUninomial(epi[0]);
798 nameToBeFilled.setSpecificEpithet(epi[1]);
799 nameToBeFilled.setInfraSpecificEpithet(epi[epi.length - 1]);
800 int lenSpecies = 2 + epi[0].length()+epi[1].length();
801 int lenInfraSpecies = 2 + epi[epi.length - 2].length() + epi[epi.length - 1].length();
802 authorString = fullNameString.substring(lenSpecies, fullNameString.length() - lenInfraSpecies);
803 }
804 //infraSpecies
805 else if (infraSpeciesPattern.matcher(fullNameString).matches()){
806 String infraSpecRankEpi = epi[2];
807 String infraSpecEpi = epi[3];
808 if ("tax.".equals(infraSpecRankEpi)){
809 infraSpecRankEpi += " " + epi[3];
810 infraSpecEpi = epi[4];
811 }
812 nameToBeFilled.setRank(Rank.getRankByAbbreviation(infraSpecRankEpi));
813 nameToBeFilled.setGenusOrUninomial(epi[0]);
814 nameToBeFilled.setSpecificEpithet(epi[1]);
815 nameToBeFilled.setInfraSpecificEpithet(infraSpecEpi);
816 authorString = fullNameString.substring(epi[0].length()+ 1 + epi[1].length() +1 + infraSpecRankEpi.length() + 1 + infraSpecEpi.length());
817 }//old infraSpecies
818 else if (oldInfraSpeciesPattern.matcher(fullNameString).matches()){
819 boolean implemented = false;
820 if (implemented){
821 nameToBeFilled.setRank(Rank.getRankByNameOrAbbreviation(epi[2]));
822 nameToBeFilled.setGenusOrUninomial(epi[0]);
823 nameToBeFilled.setSpecificEpithet(epi[1]);
824 //TODO result.setUnnamedNamePhrase(epi[2] + " " + epi[3]);
825 authorString = fullNameString.substring(epi[0].length()+ 1 + epi[1].length() +1 + epi[2].length() + 1 + epi[3].length());
826 }else{
827 nameToBeFilled.addParsingProblem(ParserProblem.OldInfraSpeciesNotSupported);
828 nameToBeFilled.setTitleCache(fullNameString);
829 // FIXME Quick fix, otherwise search would not deilver results for unparsable names
830 nameToBeFilled.setNameCache(fullNameString);
831 // END
832 logger.info("Name string " + fullNameString + " could not be parsed because UnnnamedNamePhrase is not yet implemented!");
833 }
834 }
835 //none
836 else{
837 nameToBeFilled.addParsingProblem(ParserProblem.UnparsableNamePart);
838 nameToBeFilled.setTitleCache(fullNameString);
839 // FIXME Quick fix, otherwise search would not deilver results for unparsable names
840 nameToBeFilled.setNameCache(fullNameString);
841 // END
842 logger.info("no applicable parsing rule could be found for \"" + fullNameString + "\"");
843 }
844 //authors
845 if (nameToBeFilled != null && authorString != null && authorString.trim().length() > 0 ){
846 TeamOrPersonBase<?>[] authors = new TeamOrPersonBase[4];
847 Integer[] years = new Integer[4];
848 try {
849 Class<? extends NonViralName> clazz = nameToBeFilled.getClass();
850 fullAuthors(authorString, authors, years, clazz);
851 } catch (StringNotParsableException e) {
852 nameToBeFilled.addParsingProblem(ParserProblem.UnparsableAuthorPart);
853 nameToBeFilled.setTitleCache(fullNameString);
854 // FIXME Quick fix, otherwise search would not deilver results for unparsable names
855 nameToBeFilled.setNameCache(fullNameString);
856 // END
857 logger.info("no applicable parsing rule could be found for \"" + fullNameString + "\"");;
858 }
859 nameToBeFilled.setCombinationAuthorTeam(authors[0]);
860 nameToBeFilled.setExCombinationAuthorTeam(authors[1]);
861 nameToBeFilled.setBasionymAuthorTeam(authors[2]);
862 nameToBeFilled.setExBasionymAuthorTeam(authors[3]);
863 if (nameToBeFilled instanceof ZoologicalName){
864 ZoologicalName zooName = (ZoologicalName)nameToBeFilled;
865 zooName.setPublicationYear(years[0]);
866 zooName.setOriginalPublicationYear(years[2]);
867 }
868 }
869 //return
870 if (nameToBeFilled != null){
871 //return(BotanicalName)result;
872 return;
873 }
874 } catch (UnknownCdmTypeException e) {
875 nameToBeFilled.addParsingProblem(ParserProblem.RankNotSupported);
876 nameToBeFilled.setTitleCache(fullNameString);
877 // FIXME Quick fix, otherwise search would not deilver results for unparsable names
878 nameToBeFilled.setNameCache(fullNameString);
879 // END
880 logger.info("unknown rank (" + (rank == null? "null":rank) + ") or abbreviation in string " + fullNameString);
881 //return result;
882 return;
883 }
884 }
885
886
887
888 /**
889 * Guesses the rank of uninomial depending on the typical endings for ranks
890 * @param nameToBeFilled
891 * @param string
892 */
893 private Rank guessUninomialRank(NonViralName nameToBeFilled, String uninomial) {
894 Rank result = Rank.GENUS();
895 if (nameToBeFilled.isInstanceOf(BotanicalName.class)){
896 if (false){
897 //
898 }else if (uninomial.endsWith("phyta") || uninomial.endsWith("mycota") ){ //plants, fungi
899 result = Rank.SECTION_BOTANY();
900 }else if (uninomial.endsWith("bionta")){
901 result = Rank.SUBKINGDOM(); //TODO
902 }else if (uninomial.endsWith("phytina")|| uninomial.endsWith("mycotina") ){ //plants, fungi
903 result = Rank.SUBSECTION_BOTANY();
904 }else if (uninomial.endsWith("opsida") || uninomial.endsWith("phyceae") || uninomial.endsWith("mycetes")){ //plants, algae, fungi
905 result = Rank.CLASS();
906 }else if (uninomial.endsWith("idae") || uninomial.endsWith("phycidae") || uninomial.endsWith("mycetidae")){ //plants, algae, fungi
907 result = Rank.SUBCLASS();
908 }else if (uninomial.endsWith("ales")){
909 result = Rank.ORDER();
910 }else if (uninomial.endsWith("ineae")){
911 result = Rank.SUBORDER();
912 }else if (uninomial.endsWith("aceae")){
913 result = Rank.FAMILY();
914 }else if (uninomial.endsWith("oideae")){
915 result = Rank.SUBFAMILY();
916 }else if (uninomial.endsWith("eae")){
917 result = Rank.TRIBE();
918 }else if (uninomial.endsWith("inae")){
919 result = Rank.SUBTRIBE();
920 }else if (uninomial.endsWith("ota")){
921 result = Rank.KINGDOM(); //TODO
922 }
923 }else if (nameToBeFilled.isInstanceOf(ZoologicalName.class)){
924 if (false){
925 //
926 }else if (uninomial.endsWith("oideae")){
927 result = Rank.SUPERFAMILY();
928 }else if (uninomial.endsWith("idae")){
929 result = Rank.FAMILY();
930 }else if (uninomial.endsWith("inae")){
931 result = Rank.SUBFAMILY();
932 }else if (uninomial.endsWith("inae")){
933 result = Rank.SUBFAMILY();
934 }else if (uninomial.endsWith("ini")){
935 result = Rank.TRIBE();
936 }else if (uninomial.endsWith("ina")){
937 result = Rank.SUBTRIBE();
938 }
939 }else{
940 //
941 }
942 return result;
943 }
944
945 /**
946 * Parses the fullAuthorString
947 * @param fullAuthorString
948 * @return array of Teams containing the Team[0],
949 * ExTeam[1], BasionymTeam[2], ExBasionymTeam[3]
950 */
951 protected void fullAuthors (String fullAuthorString, TeamOrPersonBase<?>[] authors, Integer[] years, Class<? extends NonViralName> clazz)
952 throws StringNotParsableException{
953 fullAuthorString = fullAuthorString.trim();
954 if (fullAuthorString == null || clazz == null){
955 return;
956 }
957 //Botanic
958 if ( BotanicalName.class.isAssignableFrom(clazz) ){
959 if (! fullBotanicAuthorStringPattern.matcher(fullAuthorString).matches() ){
960 throw new StringNotParsableException("fullAuthorString (" +fullAuthorString+") not parsable: ");
961 }
962 }
963 //Zoo
964 else if ( ZoologicalName.class.isAssignableFrom(clazz) ){
965 if (! fullZooAuthorStringPattern.matcher(fullAuthorString).matches() ){
966 throw new StringNotParsableException("fullAuthorString (" +fullAuthorString+") not parsable: ");
967 }
968 }else {
969 //TODO
970 logger.warn ("not yet implemented");
971 throw new StringNotParsableException("fullAuthorString (" +fullAuthorString+") not parsable: ");
972 }
973 fullAuthorsChecked(fullAuthorString, authors, years);
974 }
975
976 /*
977 * like fullTeams but without trim and match check
978 */
979 protected void fullAuthorsChecked (String fullAuthorString, TeamOrPersonBase<?>[] authors, Integer[] years){
980 int authorTeamStart = 0;
981 Matcher basionymMatcher = basionymPattern.matcher(fullAuthorString);
982
983 if (basionymMatcher.find(0)){
984
985 String basString = basionymMatcher.group();
986 basString = basString.replaceFirst(basStart, "");
987 basString = basString.replaceAll(basEnd, "").trim();
988 authorTeamStart = basionymMatcher.end(1) + 1;
989
990 TeamOrPersonBase<?>[] basAuthors = new TeamOrPersonBase[2];
991 Integer[] basYears = new Integer[2];
992 authorsAndEx(basString, basAuthors, basYears);
993 authors[2]= basAuthors[0];
994 years[2] = basYears[0];
995 authors[3]= basAuthors[1];
996 years[3] = basYears[1];
997 }
998 if (fullAuthorString.length() >= authorTeamStart){
999 TeamOrPersonBase<?>[] combinationAuthors = new TeamOrPersonBase[2];;
1000 Integer[] combinationYears = new Integer[2];
1001 authorsAndEx(fullAuthorString.substring(authorTeamStart), combinationAuthors, combinationYears);
1002 authors[0]= combinationAuthors[0] ;
1003 years[0] = combinationYears[0];
1004 authors[1]= combinationAuthors[1];
1005 years[1] = combinationYears[1];
1006 }
1007 }
1008
1009
1010 /**
1011 * Parses the author and ex-author String
1012 * @param authorTeamString String representing the author and the ex-author team
1013 * @return array of Teams containing the Team[0] and the ExTeam[1]
1014 */
1015 protected void authorsAndEx (String authorTeamString, TeamOrPersonBase<?>[] authors, Integer[] years){
1016 //TODO noch allgemeiner am anfang durch Replace etc.
1017 authorTeamString = authorTeamString.trim();
1018 authorTeamString = authorTeamString.replaceFirst(oWs + "ex" + oWs, " ex. " );
1019 int authorEnd = authorTeamString.length();
1020
1021 Matcher exAuthorMatcher = exAuthorPattern.matcher(authorTeamString);
1022 if (exAuthorMatcher.find(0)){
1023 int exAuthorBegin = exAuthorMatcher.end(0);
1024 String exString = authorTeamString.substring(exAuthorBegin).trim();
1025 authorEnd = exAuthorMatcher.start(0);
1026 authors [1] = author(exString);
1027 }
1028 zooOrBotanicAuthor(authorTeamString.substring(0, authorEnd), authors, years );
1029 }
1030
1031 /**
1032 * Parses the authorString and if it matches an botanical or zoological authorTeam it fills
1033 * the computes the AuthorTeam and fills it into the first field of the team array. Same applies
1034 * to the year in case of an zoological name.
1035 * @param authorString
1036 * @param team
1037 * @param year
1038 */
1039 protected void zooOrBotanicAuthor(String authorString, TeamOrPersonBase<?>[] team, Integer[] year){
1040 if (authorString == null){
1041 return;
1042 }else if ((authorString = authorString.trim()).length() == 0){
1043 return;
1044 }
1045 Matcher zooAuthorAddidtionMatcher = zooAuthorAddidtionPattern.matcher(authorString);
1046 if (zooAuthorAddidtionMatcher.find()){
1047 int index = zooAuthorAddidtionMatcher.start(0);
1048 String strYear = authorString.substring(index);
1049 strYear = strYear.replaceAll(zooAuthorYearSeperator, "").trim();
1050 year[0] = Integer.valueOf(strYear);
1051 authorString = authorString.substring(0, index).trim();
1052 }
1053 team[0] = author(authorString);
1054 }
1055
1056
1057 /**
1058 * Parses an authorTeam String and returns the Team
1059 * !!! TODO (atomization not yet implemented)
1060 * @param authorTeamString String representing the author team
1061 * @return an Team
1062 */
1063 protected TeamOrPersonBase<?> author (String authorString){
1064 if (authorString == null){
1065 return null;
1066 }else if ((authorString = authorString.trim()).length() == 0){
1067 return null;
1068 }else if (! teamSplitterPattern.matcher(authorString).find()){
1069 //1 Person
1070 Person result = Person.NewInstance();
1071 result.setNomenclaturalTitle(authorString);
1072 return result;
1073 }else{
1074 return parsedTeam(authorString);
1075 }
1076
1077 }
1078
1079 /**
1080 * Parses an authorString (reprsenting a team into the single authors and add
1081 * them to the return Team.
1082 * @param authorString
1083 * @return Team
1084 */
1085 protected Team parsedTeam(String authorString){
1086 Team result = Team.NewInstance();
1087 String[] authors = authorString.split(teamSplitter);
1088 for (String author : authors){
1089 Person person = Person.NewInstance();
1090 person.setNomenclaturalTitle(author);
1091 result.addTeamMember(person);
1092 }
1093 return result;
1094 }
1095
1096
1097 //Parsing of the given full name that has been identified as hybrid already somewhere else.
1098 private BotanicalName parseHybrid(String fullName){
1099 logger.warn("parseHybrid --> function not yet implemented");
1100 BotanicalName result = BotanicalName.NewInstance(null);
1101 result.setTitleCache(fullName);
1102 return result;
1103 }
1104
1105 // // Parsing of the given full name that has been identified as a cultivar already somwhere else.
1106 // // The ... cv. ... syntax is not covered here as it is not according the rules for naming cultivars.
1107 public BotanicalName parseCultivar(String fullName) throws StringNotParsableException{
1108 CultivarPlantName result = null;
1109 String[] words = oWsPattern.split(fullName);
1110
1111 /* ---------------------------------------------------------------------------------
1112 * cultivar
1113 * ---------------------------------------------------------------------------------*/
1114 if (fullName.indexOf(" '") != 0){
1115 //TODO location of 'xx' is probably not arbitrary
1116 Matcher cultivarMatcher = cultivarPattern.matcher(fullName);
1117 if (cultivarMatcher.find()){
1118 String namePart = fullName.replaceFirst(cultivar, "");
1119
1120 String cultivarPart = cultivarMatcher.group(0).replace("'","").trim();
1121 //OLD: String cultivarPart = cultivarRE.getParen(0).replace("'","").trim();
1122
1123 result = (CultivarPlantName)parseFullName(namePart);
1124 result.setCultivarName(cultivarPart);
1125 }
1126 }else if (fullName.indexOf(" cv.") != 0){
1127 // cv. is old form (not official)
1128 throw new StringNotParsableException("Cultivars with only cv. not yet implemented in name parser!");
1129 }
1130
1131 /* ---------------------------------------------------------------------------------
1132 * cultivar group
1133 * ---------------------------------------------------------------------------------
1134 */
1135 // TODO in work
1136 //Ann. this is not the official way of noting cultivar groups
1137 String group = oWs + "Group" + oWs + capitalEpiWord + end;
1138 Pattern groupRE = Pattern.compile(group);
1139 Matcher groupMatcher = groupRE.matcher(fullName);
1140 if (groupMatcher.find()){
1141 if (! words[words.length - 2].equals("group")){
1142 throw new StringNotParsableException ("fct ParseHybrid --> term before cultivar group name in " + fullName + " should be 'group'");
1143 }else{
1144
1145 String namePart = fullName.substring(0, groupMatcher.start(0) - 0);
1146 //OLD: String namePart = fullName.substring(0, groupRE.getParenStart(0) - 0);
1147
1148 String cultivarPart = words[words.length -1];
1149 result = (CultivarPlantName)parseFullName(namePart);
1150 if (result != null){
1151 result.setCultivarName(cultivarPart);
1152
1153 //OLD: result.setCultivarGroupName(cultivarPart);
1154 }
1155 }
1156
1157 }
1158 // // ---------------------------------------------------------------------------------
1159 // if ( result = "" ){
1160 // return "I: fct ParseCultivar: --> could not parse cultivar " + fullName;
1161 // }else{
1162 // return result;
1163 // }
1164 return result; //TODO
1165 }
1166
1167
1168 private void makeEmpty(NonViralName nameToBeFilled){
1169 nameToBeFilled.setRank(null);
1170 nameToBeFilled.setTitleCache(null, false);
1171 nameToBeFilled.setFullTitleCache(null, false);
1172 nameToBeFilled.setNameCache(null, false);
1173
1174 nameToBeFilled.setAppendedPhrase(null);
1175 nameToBeFilled.setBasionymAuthorTeam(null);
1176 nameToBeFilled.setCombinationAuthorTeam(null);
1177 nameToBeFilled.setExBasionymAuthorTeam(null);
1178 nameToBeFilled.setExCombinationAuthorTeam(null);
1179 nameToBeFilled.setAuthorshipCache(null, false);
1180
1181
1182 //delete problems except check rank
1183 makeProblemEmpty(nameToBeFilled);
1184
1185 // TODO ?
1186 //nameToBeFilled.setHomotypicalGroup(newHomotypicalGroup);
1187
1188
1189 nameToBeFilled.setGenusOrUninomial(null);
1190 nameToBeFilled.setInfraGenericEpithet(null);
1191 nameToBeFilled.setSpecificEpithet(null);
1192 nameToBeFilled.setInfraSpecificEpithet(null);
1193
1194 nameToBeFilled.setNomenclaturalMicroReference(null);
1195 nameToBeFilled.setNomenclaturalReference(null);
1196
1197 nameToBeFilled.setHybridFormula(false);
1198 nameToBeFilled.setMonomHybrid(false);
1199 nameToBeFilled.setBinomHybrid(false);
1200 nameToBeFilled.setTrinomHybrid(false);
1201
1202 if (nameToBeFilled.isInstanceOf(BotanicalName.class)){
1203 BotanicalName botanicalName = (BotanicalName)nameToBeFilled;
1204 botanicalName.setAnamorphic(false);
1205 }
1206
1207 if (nameToBeFilled.isInstanceOf(ZoologicalName.class)){
1208 ZoologicalName zoologicalName = (ZoologicalName)nameToBeFilled;
1209 zoologicalName.setBreed(null);
1210 zoologicalName.setOriginalPublicationYear(null);
1211
1212 }
1213 }
1214
1215
1216
1217 }