Error: NoSuchElementException - java.util.scanner

This program accesses a text file with text elements separated by commas. The elements register in the variables I created. Except for the last one. The error then occurs. The program works fine with the default whitespace delimitor for the scanner class (the text file is adjusted accodingly) but fails when I use a comma as the delimitor. Could someone please supply some insight.
Text Data:
smith,john,10
stiles,pat,12
mason,emrick,12
Code:
public void openFile(String f)
{
try{
x = new Scanner(new File(f));
x.useDelimiter(",");
} catch(Exception e){
System.out.println("File could not be found please check filepath");
}
}
public boolean checkNameRoster()
{
openFile(file);
boolean b = false;
while(x.hasNext())
{
String lName = x.next().trim();
**String fName = x.next().trim();**
String grade = x.next().trim();
if(fName.equalsIgnoreCase(firstName) && lName.equalsIgnoreCase(lastName) && grade.equalsIgnoreCase(grade))
{
b = true;
}
}
closeFile();
return b;
}

The problem relies on the fact that you called x.useDelimiter(","); on your Scanner in function openFile().
Since your text data is:
smith,john,10
stiles,pat,12
mason,emrick,12
the Scanner sees it as:
"smith,john,10\nstiles,pat,12\nmason,emrick,12"
So what happens when you execute your code is:
1: x.hasNext() ? Yes
x.next().trim() => "smith"
x.next().trim() => "john"
x.next().trim() => "10\nstiles"
2: x.hasNext() ? Yes
x.next().trim() => "pat"
x.next().trim() => "12\nmason"
x.next().trim() => "emrick"
3: x.hasNext() ? Yes
x.next().trim() => "12"
x.next().trim() => Error!
To fix this you can either edit the file and change all the \n with ,, or use a first Scanner to get all the lines, and another one to get the tokens, as shown here:
public void openFile(String f)
{
try{
x = new Scanner(new File(f)); // Leave default delimiter
} catch(Exception e){
System.out.println("File could not be found please check filepath");
}
}
public boolean checkNameRoster()
{
openFile(file);
boolean b = false;
while(x.hasNextLine()) // For each line in your file
{
Scanner tk = new Scanner(x.nextLine()).useDelimiter(","); // Scan the current line
String lName = x.next().trim();
String fName = x.next().trim();
String grade = x.next().trim();
if (fName.equalsIgnoreCase(firstName) && lName.equalsIgnoreCase(lastName) && grade.equalsIgnoreCase(grade))
{
b = true;
}
}
closeFile();
return b;
}

Related

Weired problem after reading input from keyboard

edit: The ArrayList wasn't needed to reproduce the "error". Sorry for this delay, but know it should be much clearer.
Why is:
c2.number.equals(c3.number) = false
I really expected a true here. There must be something wrong with my equals method?
Why on earth do I need to write more text...
package com.example.mypackage;
import java.util.ArrayList;
import java.util.Scanner;
class Contact {
public String name;
public String number;
public Contact(String name, String number) {
this.name = name;
this.number = number;
}
public void print(){
System.out.println(name+number);
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj == null) {
return false;
} else if (obj instanceof Contact) {
Contact contact = (Contact) obj;
if ((contact.name == this.name && contact.number == this.number)) {
return true;
}
}
return false;
}
}
public class Main {
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
Contact c1 = new Contact("ben", "1");
c1.print();
Contact c2 = new Contact("ben", "1");
c2.print();
System.out.println("name : ");
String name=scanner.nextLine();
System.out.println("number");
String number=scanner.nextLine();
Contact c3=new Contact(name, number);
c3.print();
System.out.println("c1.equals(c2) = "+c1.equals(c2));
System.out.println("c3 instanceof Contact = "+(c3 instanceof Contact));
System.out.println("c2.name.equals(c3.name) = "+c2.name.equals(c3.name));
System.out.println("c2.number.equals(c3.number) = "+c2.number.equals(c3.number));
System.out.println("c2.number.equals(c3.number) = "+c3.equals(c2));
}
}
Output is:
ben1
ben1
name :
ben
number
1
ben1
c1.equals(c2) = true
c3 instanceof Contact = true
c2.name.equals(c3.name) = true
c2.number.equals(c3.number) = true
c2.number.equals(c3.number) = false
Process finished with exit code 0
Why is:
c2.number.equals(c3.number) = false
I really expected a true here. There must be something wrong with my equals method?
Why on earth do I need to write more text...
Why is:
c2.number.equals(c3.number) = false
I really expected a true here. There must be something wrong with my equals method?
Why on earth do I need to write more text...
Why is:
c2.number.equals(c3.number) = false
I really expected a true here. There must be something wrong with my equals method?
Why on earth do I need to write more text...
Ah finally I got it. The error is in the equals method.
I must use "equals()" instead of "==" there. For some reason this comparison does work with c1 and c2 but not with c3.
-1 is returned if it wasn't found in the list.
Did you forget to myList.add() it?
The only add I see is when you added c1.
You need to myList.add(c3) after you get the input, or it won't be in the list to find an index of.

String comparison not working for sharepoint multiline text values

I am fetching data from sharepoint list for a multi line column.
And then split the data by space and comparing it to other string but despite the value in both the strings being same it gives false result.
Please follow the below code:
string[] strBodys = SPHttpUtility.ConvertSimpleHtmlToText(Convert.ToString(workflowProperties.ListItem[SCMSConstants.lstfldBody]), Convert.ToString(workflowProperties.ListItem[SCMSConstants.lstfldBody]).Length).Split(' ');
bool hasKwrdInBody = false;
foreach (SPItem oItem in oColl)
{//get all the keywords
string[] strkeyWrds = SPHttpUtility.ConvertSimpleHtmlToText(Convert.ToString(oItem[SCMSConstants.lstfldKWConfigKeywordsIntrName]), Convert.ToString(oItem[SCMSConstants.lstfldKWConfigKeywordsIntrName]).Length).Split(',');
//in body
foreach (string strKW in strkeyWrds)
{
string KWValue = strKW.Trim(' ').ToLower();
foreach (string strBdy in strBodys)
{
string BodyValue = strBdy.Trim(' ').ToLower();
//if (strKW.ToLower().Equals(strBdy.ToLower()))
if(KWValue == BodyValue) //here it always gives false result
{
hasKwrdInBody = true;
break;
}
}
if (hasKwrdInBody)
break;
}
if (!hasKwrdInSbjct && !hasKwrdInBody)
{
continue;
}
else
{
//set business unit to current groups rule
bsnsUnitLookupFld = new SPFieldLookupValue(Convert.ToString(oItem[SCMSConstants.lstfldBsnsUnit]));
asgndTo = new SPFieldUserValue(objWeb,Convert.ToString(oItem[SCMSConstants.lstfldKWConfigAssignedToIntrName])).User;
groupName = Convert.ToString(oItem[SCMSConstants.lstfldKWConfigAssignedToGroupIntrName]).Split('#').Last();
break;
}
}
Please mind that i am trying to get multi line text from sharepoint list
Please provide your suggestions.
That also depends on the exact type of your Multiline field (e.g Plain Text or RichText, etc.).
Maybe it would be clear if you just added some logging writing out the values you are comparing.
For details on how to get the value of a Multiline textfield check Accessing Multiple line of text programmatically
and here for RichText
I got it working by comparing and counting the characters in both the strings. Actually some UTC codes were embedded in to the string. First I removed those characters using regular expression and then compared them and it worked like a charm.
Here is the code snippet, might help some one.
string[] strBodys = SPHttpUtility.ConvertSimpleHtmlToText(Convert.ToString(workflowProperties.ListItem[SCMSConstants.lstfldBody]), Convert.ToString(workflowProperties.ListItem[SCMSConstants.lstfldBody]).Length).Split(' ');
bool hasKwrdInBody = false;
foreach (SPItem oItem in oColl)
{//get all the keywords
string[] strkeyWrds = SPHttpUtility.ConvertSimpleHtmlToText(Convert.ToString(oItem[SCMSConstants.lstfldKWConfigKeywordsIntrName]), Convert.ToString(oItem[SCMSConstants.lstfldKWConfigKeywordsIntrName]).Length).Split(',');
//in body
foreach (string strKW in strkeyWrds)
{
string KWValue = strKW.Trim(' ').ToLower();
KWValue = Regex.Replace(KWValue, #"[^\u0000-\u007F]", string.Empty); //here replaced the utc codes
foreach (string strBdy in strBodys)
{
string BodyValue = strBdy.Trim(' ').ToLower();
BodyValue = Regex.Replace(BodyValue, #"\t|\n|\r", string.Empty); // new code to replace utc code
BodyValue = Regex.Replace(BodyValue, #"[^\u0000-\u007F]", string.Empty); //new code to replace utc code
//if (strKW.ToLower().Equals(strBdy.ToLower()))
if(KWValue == BodyValue) //here it always gives false result
{
hasKwrdInBody = true;
break;
}
}
if (hasKwrdInBody)
break;
}
if (!hasKwrdInSbjct && !hasKwrdInBody)
{
continue;
}
else
{
//set business unit to current groups rule
bsnsUnitLookupFld = new SPFieldLookupValue(Convert.ToString(oItem[SCMSConstants.lstfldBsnsUnit]));
asgndTo = new SPFieldUserValue(objWeb,Convert.ToString(oItem[SCMSConstants.lstfldKWConfigAssignedToIntrName])).User;
groupName = Convert.ToString(oItem[SCMSConstants.lstfldKWConfigAssignedToGroupIntrName]).Split('#').Last();
break;
}
}

boolean to string in TableView JavaFx

im trying to display a boolean value as a string in a tableview so instead of true i want to display male.
i'm a bit lost with it to be honest. i cant find anything on the internet to help.
the error ecilpse is giving me is The method " setCellValueFactory(Callback,ObservableValue>) in the type TableColumn is not applicable for the arguments (( cellData) -> {})"
heres my code. its probably wrong
TableColumn<Animal, String > genColumn = new TableColumn<>("Male");
genColumn.setMinWidth(50);
genColumn.setCellValueFactory(cellData -> {
boolean gender = cellData.getValue().getGender();
String genderAsString;
if(gender == true)
{
genderAsString = "Male";
}
else
{
genderAsString = "Female";
}
new ReadOnlyStringWrapper(genderAsString);
});
i would be grateful for any help thanks
Keep the type as boolean and use a cell factory to change the way you display it:
TableColumn<Animal, Boolean> genColumn = new TableColumn<>("Gender");
genColumn.setCellValueFactory(cellData -> cellData.getValue().genderProperty());
// or cellData -> new SimpleBooleanProperty(cellData.getValue().getGender())
// if your model class doesn't use JavaFX properties
genColumn.setCellFactory(col -> new TableCell<Animal, Boolean>() {
#Override
protected void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty) ;
setText(empty ? null : item ? "Male" : "Female" );
}
});
i managed to get it working i was just missing the return statement.
heres the code
TableColumn<Animal, String > genColumn = new TableColumn<>("Gender");
genColumn.setMinWidth(50);
genColumn.setCellValueFactory(cellData -> {
boolean gender = cellData.getValue().getGender();
String genderAsString;
if(gender == true)
{
genderAsString = "Male";
}
else
{
genderAsString = "Female";
}
return new ReadOnlyStringWrapper(genderAsString);
});

How to pass multiple list types as a parameter using the same method variable

I'm trying to pass multiple list types as a parameter using the same method variable and then loop through the types based on which type as been past. I tried using a generic method but it's not working. Below are pseudo/example codes. The List SAS_F_DISAGG_F and List SAS_C_DISAGG_C are SQL/Entity, and the List DisaggReportGroups is a class object. I'm trying to pass the entity lists.
protected void GetReportGroup()
{
DisaggReportGroups rptGroup = new DisaggReportGroups();
List<DisaggReportGroups> disagreportGroup = new List<DisaggReportGroups>();
disagreportGroup.Add(rptGroup);
DisaggregatedReportData disagReportData = new DisaggregatedReportData();
foreach (var reportGroup in disagreportGroup)
{
if (reportGroup.FuturesOnly == "Futures Only, " & reportGroup.Agriculture == "Agriculture")
{
List<SAS_F_DISAGG_F> futONlyDisagReportData = disagReportData.GetFuturesOnlyReportData(reportGroup.Agriculture).ToList();
CreateLongFormatReport<List<SAS_F_DISAGG_F>>(reportGroup.AgricultureFilenameFOLF, reportGroup.FuturesOnly, reportGroup.Agriculture, futONlyDisagReportData);
}
else if (reportGroup.FOCombined == "Futures and Options Combined, " & reportGroup.Agriculture == "Agriculture")
{
List<SAS_C_DISAGG_C> combinedDisagReportData = disagReportData.GetFOCombinedReportData(reportGroup.Agriculture).ToList();
CreateLongFormatReport<List<SAS_C_DISAGG_C>>(reportGroup.AgricultureFilenameFOCombinedLF, reportGroup.FOCombined, reportGroup.Agriculture, combinedDisagReportData);
}
}
}
protected void CreateFormatReport<T>(string filename, string disagCategory, string commSubGp, List<T> reportData)
{
using (FileStream fileStream = new FileStream(Server.MapPath(#"~/Includes/") + filename, FileMode.Create))
{
using (StreamWriter writer = new StreamWriter(fileStream))
{
foreach (var value in reportData)
{
string FuturesOnly = "Futures Only, ";
string FOCombined = "Futures and Options Combined, ";
string reportCategory = "";
if (disagCategory == FuturesOnly)
{
reportCategory = FuturesOnly;
}
else if (disagCategory == FOCombined)
{
reportCategory = FOCombined;
}
string row01 = String.Format("{0, -10}{1, 29}{2, 8}", value.MKTTITL.PadRight(120), "Code -", value.Conmkt);
string row02 = String.Format("{0, -10}{1, 7}{2, 14}", "Blah Blah - ", reportCategory, value.DAT1TITL);
string row03 = String.Format("{0, 3}{1, 3}{2, 8:0,0}{3, 3}{4, 8:0,0}{5, 11:0,0}{6, 11:0,0}{7, 11:0,0}{8, 11:0,0}{9, 13:0,0}{10, 11:0,0}{11, 11:0,0}{12, 13:0,0}{13, 10:0,0}{14, 9:0,0}{15, 3}{16, 8:0,0}{17, 10:0,0}", "All",
colon, value.TA01, colon, value.TA02, value.TA03, value.TA04, value.TA05, value.TA06, value.TA07, value.TA08, value.TA09, value.TA10, value.TA11, value.TA12, colon, value.TA15, value.TA16);
string row04 = String.Format("{0, 3}{1, 3}{2, 8:0,0}{3, 3}{4, 8:0,0}{5, 11:0,0}{6, 11:0,0}{7, 11:0,0}{8, 11:0.##}{9, 13:0,0}{10, 11:0,0}{11, 11:0,0}{12, 13:0,0}{13, 10:0,0}{14, 9:0,0}{15, 3}{16, 8:0,0}{17, 10:0,0}", "Old",
colon, value.TO01, colon, value.TO02, value.TO03, value.TO04, value.TO05, value.TO06, value.TO07, value.TO08, value.TO09, value.TO10, value.TO11, value.TO12, colon, value.TO15, value.TO16);
writer.Write(row01);
writer.WriteLine(row02);
writer.WriteLine(row03);
writer.WriteLine(row04);
} //end foreach
writer.Close();
} //end of stream writer
}
}
Thanks for your help.
I managed to solve this problem myself so I'm posting my solution for others that may need the same type of help. The solution is to use Reflection within the foreach iteration.
foreach (var value in ReportData)
{
//Reflection can be used
string TA01 = value.GetType().GetProperty("TA01").GetValue(value).ToString();
//...
//...
//do more stuff/coding...
}
Then in the String.Format change "value.TA01" to "TA01". Do the same for all other variables.
Hope this help.

Multi-term named entities in Stanford Named Entity Recognizer

I'm using the Stanford Named Entity Recognizer http://nlp.stanford.edu/software/CRF-NER.shtml and it's working fine. This is
List<List<CoreLabel>> out = classifier.classify(text);
for (List<CoreLabel> sentence : out) {
for (CoreLabel word : sentence) {
if (!StringUtils.equals(word.get(AnswerAnnotation.class), "O")) {
namedEntities.add(word.word().trim());
}
}
}
However the problem I'm finding is identifying names and surnames. If the recognizer encounters "Joe Smith", it is returning "Joe" and "Smith" separately. I'd really like it to return "Joe Smith" as one term.
Could this be achieved through the recognizer maybe through a configuration? I didn't find anything in the javadoc till now.
Thanks!
This is because your inner for loop is iterating over individual tokens (words) and adding them separately. You need to change things to add whole names at once.
One way is to replace the inner for loop with a regular for loop with a while loop inside it which takes adjacent non-O things of the same class and adds them as a single entity.*
Another way would be to use the CRFClassifier method call:
List<Triple<String,Integer,Integer>> classifyToCharacterOffsets(String sentences)
which will give you whole entities, which you can extract the String form of by using substring on the original input.
*The models that we distribute use a simple raw IO label scheme, where things are labeled PERSON or LOCATION, and the appropriate thing to do is simply to coalesce adjacent tokens with the same label. Many NER systems use more complex labels such as IOB labels, where codes like B-PERS indicates where a person entity starts. The CRFClassifier class and feature factories support such labels, but they're not used in the models we currently distribute (as of 2012).
The counterpart of the classifyToCharacterOffsets method is that (AFAIK) you can't access the label of the entities.
As proposed by Christopher, here is an example of a loop which assembles "adjacent non-O things". This example also counts the number of occurrences.
public HashMap<String, HashMap<String, Integer>> extractEntities(String text){
HashMap<String, HashMap<String, Integer>> entities =
new HashMap<String, HashMap<String, Integer>>();
for (List<CoreLabel> lcl : classifier.classify(text)) {
Iterator<CoreLabel> iterator = lcl.iterator();
if (!iterator.hasNext())
continue;
CoreLabel cl = iterator.next();
while (iterator.hasNext()) {
String answer =
cl.getString(CoreAnnotations.AnswerAnnotation.class);
if (answer.equals("O")) {
cl = iterator.next();
continue;
}
if (!entities.containsKey(answer))
entities.put(answer, new HashMap<String, Integer>());
String value = cl.getString(CoreAnnotations.ValueAnnotation.class);
while (iterator.hasNext()) {
cl = iterator.next();
if (answer.equals(
cl.getString(CoreAnnotations.AnswerAnnotation.class)))
value = value + " " +
cl.getString(CoreAnnotations.ValueAnnotation.class);
else {
if (!entities.get(answer).containsKey(value))
entities.get(answer).put(value, 0);
entities.get(answer).put(value,
entities.get(answer).get(value) + 1);
break;
}
}
if (!iterator.hasNext())
break;
}
}
return entities;
}
I had the same problem, so I looked it up, too. The method proposed by Christopher Manning is efficient, but the delicate point is to know how to decide which kind of separator is appropriate. One could say only a space should be allowed, e.g. "John Zorn" >> one entity. However, I may find the form "J.Zorn", so I should also allow certain punctuation marks. But what about "Jack, James and Joe" ? I might get 2 entities instead of 3 ("Jack James" and "Joe").
By digging a bit in the Stanford NER classes, I actually found a proper implementation of this idea. They use it to export entities under the form of single String objects. For instance, in the method PlainTextDocumentReaderAndWriter.printAnswersTokenizedInlineXML, we have:
private void printAnswersInlineXML(List<IN> doc, PrintWriter out) {
final String background = flags.backgroundSymbol;
String prevTag = background;
for (Iterator<IN> wordIter = doc.iterator(); wordIter.hasNext();) {
IN wi = wordIter.next();
String tag = StringUtils.getNotNullString(wi.get(AnswerAnnotation.class));
String before = StringUtils.getNotNullString(wi.get(BeforeAnnotation.class));
String current = StringUtils.getNotNullString(wi.get(CoreAnnotations.OriginalTextAnnotation.class));
if (!tag.equals(prevTag)) {
if (!prevTag.equals(background) && !tag.equals(background)) {
out.print("</");
out.print(prevTag);
out.print('>');
out.print(before);
out.print('<');
out.print(tag);
out.print('>');
} else if (!prevTag.equals(background)) {
out.print("</");
out.print(prevTag);
out.print('>');
out.print(before);
} else if (!tag.equals(background)) {
out.print(before);
out.print('<');
out.print(tag);
out.print('>');
}
} else {
out.print(before);
}
out.print(current);
String afterWS = StringUtils.getNotNullString(wi.get(AfterAnnotation.class));
if (!tag.equals(background) && !wordIter.hasNext()) {
out.print("</");
out.print(tag);
out.print('>');
prevTag = background;
} else {
prevTag = tag;
}
out.print(afterWS);
}
}
They iterate over each word, checking if it has the same class (answer) than the previous, as explained before. For this, they take advantage of the fact expressions considered as not being entities are flagged using the so-called backgroundSymbol (class "O"). They also use the property BeforeAnnotation, which represents the string separating the current word from the previous one. This last point allows solving the problem I initially raised, regarding the choice of an appropriate separator.
Code for the above:
<List> result = classifier.classifyToCharacterOffsets(text);
for (Triple<String, Integer, Integer> triple : result)
{
System.out.println(triple.first + " : " + text.substring(triple.second, triple.third));
}
List<List<CoreLabel>> out = classifier.classify(text);
for (List<CoreLabel> sentence : out) {
String s = "";
String prevLabel = null;
for (CoreLabel word : sentence) {
if(prevLabel == null || prevLabel.equals(word.get(CoreAnnotations.AnswerAnnotation.class)) ) {
s = s + " " + word;
prevLabel = word.get(CoreAnnotations.AnswerAnnotation.class);
}
else {
if(!prevLabel.equals("O"))
System.out.println(s.trim() + '/' + prevLabel + ' ');
s = " " + word;
prevLabel = word.get(CoreAnnotations.AnswerAnnotation.class);
}
}
if(!prevLabel.equals("O"))
System.out.println(s + '/' + prevLabel + ' ');
}
I just wrote a small logic and it's working fine. what I did is group words with same label if they are adjacent.
Make use of the classifiers already provided to you. I believe this is what you are looking for:
private static String combineNERSequence(String text) {
String serializedClassifier = "edu/stanford/nlp/models/ner/english.all.3class.distsim.crf.ser.gz";
AbstractSequenceClassifier<CoreLabel> classifier = null;
try {
classifier = CRFClassifier
.getClassifier(serializedClassifier);
} catch (ClassCastException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(classifier.classifyWithInlineXML(text));
// FOR TSV FORMAT //
//System.out.print(classifier.classifyToString(text, "tsv", false));
return classifier.classifyWithInlineXML(text);
}
Here is my full code, I use Stanford core NLP and write algorithm to concatenate Multi Term names.
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import edu.stanford.nlp.util.CoreMap;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* Created by Chanuka on 8/28/14 AD.
*/
public class FindNameEntityTypeExecutor {
private static Logger logger = Logger.getLogger(FindNameEntityTypeExecutor.class);
private StanfordCoreNLP pipeline;
public FindNameEntityTypeExecutor() {
logger.info("Initializing Annotator pipeline ...");
Properties props = new Properties();
props.setProperty("annotators", "tokenize, ssplit, pos, lemma, ner");
pipeline = new StanfordCoreNLP(props);
logger.info("Annotator pipeline initialized");
}
List<String> findNameEntityType(String text, String entity) {
logger.info("Finding entity type matches in the " + text + " for entity type, " + entity);
// create an empty Annotation just with the given text
Annotation document = new Annotation(text);
// run all Annotators on this text
pipeline.annotate(document);
List<CoreMap> sentences = document.get(CoreAnnotations.SentencesAnnotation.class);
List<String> matches = new ArrayList<String>();
for (CoreMap sentence : sentences) {
int previousCount = 0;
int count = 0;
// traversing the words in the current sentence
// a CoreLabel is a CoreMap with additional token-specific methods
for (CoreLabel token : sentence.get(CoreAnnotations.TokensAnnotation.class)) {
String word = token.get(CoreAnnotations.TextAnnotation.class);
int previousWordIndex;
if (entity.equals(token.get(CoreAnnotations.NamedEntityTagAnnotation.class))) {
count++;
if (previousCount != 0 && (previousCount + 1) == count) {
previousWordIndex = matches.size() - 1;
String previousWord = matches.get(previousWordIndex);
matches.remove(previousWordIndex);
previousWord = previousWord.concat(" " + word);
matches.add(previousWordIndex, previousWord);
} else {
matches.add(word);
}
previousCount = count;
}
else
{
count=0;
previousCount=0;
}
}
}
return matches;
}
}
Another approach to deal with multi words entities.
This code combines multiple tokens together if they have the same annotation and go in a row.
Restriction:
If the same token has two different annotations, the last one will be saved.
private Document getEntities(String fullText) {
Document entitiesList = new Document();
NERClassifierCombiner nerCombClassifier = loadNERClassifiers();
if (nerCombClassifier != null) {
List<List<CoreLabel>> results = nerCombClassifier.classify(fullText);
for (List<CoreLabel> coreLabels : results) {
String prevLabel = null;
String prevToken = null;
for (CoreLabel coreLabel : coreLabels) {
String word = coreLabel.word();
String annotation = coreLabel.get(CoreAnnotations.AnswerAnnotation.class);
if (!"O".equals(annotation)) {
if (prevLabel == null) {
prevLabel = annotation;
prevToken = word;
} else {
if (prevLabel.equals(annotation)) {
prevToken += " " + word;
} else {
prevLabel = annotation;
prevToken = word;
}
}
} else {
if (prevLabel != null) {
entitiesList.put(prevToken, prevLabel);
prevLabel = null;
}
}
}
}
}
return entitiesList;
}
Imports:
Document: org.bson.Document;
NERClassifierCombiner: edu.stanford.nlp.ie.NERClassifierCombiner;

Resources