import java.util.Arrays ;
class SentimentAnalyzer {
// Tip: labeled continue can be used when iterating featureSet + convert review to lower-case
public static int [ ] detectProsAndCons
( String review,
String [ ] [ ] featureSet,
String [ ] posOpinionWords,
int [ ] featureOpinions = new int [ featureSet.length ] ; // Initialized to 0 by default
// Pass each pro or con to getOpinionOnFeature
int index = 0 ;
for ( String [ ] ss
: featureSet
) { // For each feature for ( String s
: ss
) { // Check feature synonyms featureOpinions[ index] = getOpinionOnFeature( review.toLowerCase ( ) , s, posOpinionWords, negOpinionWords) ;
// Store the result when we find something and stop looking for more.
if ( featureOpinions[ index] != 0 ) {
index++;
break ; // Go to next feature
}
}
}
return featureOpinions;
}
// First invoke checkForWasPhrasePattern and
// if it cannot find an opinion only then invoke checkForOpinionFirstPattern
private static int getOpinionOnFeature
( String review,
String feature,
String [ ] posOpinionWords,
String [ ] negOpinionWords
) {
// Call the pattern checks
int result = checkForWasPhrasePattern( review, feature, posOpinionWords, negOpinionWords) ;
if ( result == 0 )
{
result = checkForOpinionFirstPattern( review, feature, posOpinionWords, negOpinionWords) ;
}
return result;
}
// Tip: Look at String API doc. Methods like indexOf, length, substring(beginIndex), startsWith can come into play
// Return 1 if positive opinion found, -1 for negative opinion, 0 for no opinion
// You can first look for positive opinion. If not found, only then you can look for negative opinion
private static int checkForWasPhrasePattern
( String review,
String feature,
String [ ] posOpinionWords,
String [ ] negOpinionWords
) { int opinion = 0 ;
String pattern
= feature
+ " was " ; // Let's do this without tokenizing the string around spaces, since we have this pattern string provided.
// your code
int index = review.indexOf ( pattern) ;
// If pattern matches
if ( index != - 1 ) {
// Move index to the opinion word
// Note: will go out of bounds if at end of review string, but we shouldn't be at the end of a string mid-sentence
index += pattern.length ( ) ;
// Error check
if ( index >= review.length ( ) )
return 0 ; // We have found an incomplete sentence at the end of the string.
// Since we are not out of bounds, find opinion
String sub
= review.
substring ( index
) ;
for ( String s
: posOpinionWords
) { // If we have a positive opinion
if ( sub.startsWith ( s) ) {
opinion = 1 ;
return opinion;
}
}
for ( String s
: negOpinionWords
) { // If we have a negative opinion
if ( sub.startsWith ( s) ) {
opinion = - 1 ;
return opinion;
}
}
}
// If pattern doesn't match, or no opinion was found after the pattern:
return opinion; // still 0
}
private static int checkForOpinionFirstPattern
( String review,
String feature,
String [ ] posOpinionWords,
// Extract sentences as feature might appear multiple times.
// split() takes a regular expression and "." is a special character
// for regular expression. So, escape it to make it work!!
String [ ] sentences
= review.
split ( "\\ ." ) ; int opinion = 0 ;
// Find positive adjective + feature combination
int index;
for ( String p
: posOpinionWords
) { index = s.indexOf ( feature + p) ;
// If we've found the feature + opinion, return
if ( index != - 1 ) {
opinion = 1 ; // Used explicit syntax for readability.
return opinion;
}
}
}
// Find negative adjevtive + feature combination
for ( String n
: negOpinionWords
) { index = s.indexOf ( feature + n) ;
// If we've found the feature + opinion, return
if ( index != - 1 ) {
opinion = - 1 ; // Used explicit syntax for readability.
return opinion;
}
}
}
return opinion;
}
public static void main
( String [ ] args
) { String review
= "Haven't been here in years! Fantastic service and the food was delicious! Definetly will be a frequent flyer! Francisco was very attentive" ;
//String review = "Sorry OG, but you just lost some loyal customers. Horrible service, no smile or greeting just attitude. The breadsticks were stale and burnt, appetizer was cold and the food came out before the salad.";
{ "ambiance" , "ambience" , "atmosphere" , "decor" } ,
{ "dessert" , "ice cream" , "desert" } ,
{ "food" } ,
{ "soup" } ,
{ "service" , "management" , "waiter" , "waitress" , "bartender" , "staff" , "server" } } ;
String [ ] posOpinionWords
= { "good" ,
"fantastic" ,
"friendly" ,
"great" ,
"excellent" ,
"amazing" ,
"awesome" ,
"delicious" } ;
String [ ] negOpinionWords
= { "slow" ,
"bad" ,
"horrible" ,
"awful" ,
"unprofessional" ,
"poor" } ;
int [ ] featureOpinions = detectProsAndCons( review, featureSet, posOpinionWords, negOpinionWords) ;
System .
out .
println ( "Opinions on Features: " + Arrays .
toString ( featureOpinions
) ) ; }
}
aW1wb3J0IGphdmEudXRpbC5BcnJheXM7CgpjbGFzcyBTZW50aW1lbnRBbmFseXplciB7CiAgICAvLyBUaXA6IGxhYmVsZWQgY29udGludWUgY2FuIGJlIHVzZWQgd2hlbiBpdGVyYXRpbmcgZmVhdHVyZVNldCArIGNvbnZlcnQgcmV2aWV3IHRvIGxvd2VyLWNhc2UKCXB1YmxpYyBzdGF0aWMgaW50W10gZGV0ZWN0UHJvc0FuZENvbnMoU3RyaW5nIHJldmlldywgU3RyaW5nW11bXSBmZWF0dXJlU2V0LCBTdHJpbmdbXSBwb3NPcGluaW9uV29yZHMsCgkJCVN0cmluZ1tdIG5lZ09waW5pb25Xb3JkcykgewoJCWludFtdIGZlYXR1cmVPcGluaW9ucyA9IG5ldyBpbnRbZmVhdHVyZVNldC5sZW5ndGhdOyAvLyBJbml0aWFsaXplZCB0byAwIGJ5IGRlZmF1bHQKCQkKCQkvLyBQYXNzIGVhY2ggcHJvIG9yIGNvbiB0byBnZXRPcGluaW9uT25GZWF0dXJlCgkJaW50IGluZGV4ID0gMDsKCQlmb3IgKFN0cmluZ1tdIHNzOiBmZWF0dXJlU2V0KSB7IC8vIEZvciBlYWNoIGZlYXR1cmUKCQkJZm9yIChTdHJpbmcgczogc3MpIHsJCS8vIENoZWNrIGZlYXR1cmUgc3lub255bXMKCQkJCWZlYXR1cmVPcGluaW9uc1tpbmRleF0gPSBnZXRPcGluaW9uT25GZWF0dXJlKHJldmlldy50b0xvd2VyQ2FzZSgpLCBzLCBwb3NPcGluaW9uV29yZHMsIG5lZ09waW5pb25Xb3Jkcyk7CgkJCQkvLyBTdG9yZSB0aGUgcmVzdWx0IHdoZW4gd2UgZmluZCBzb21ldGhpbmcgYW5kIHN0b3AgbG9va2luZyBmb3IgbW9yZS4KCQkJCWlmIChmZWF0dXJlT3BpbmlvbnNbaW5kZXhdICE9IDApIHsKCQkJCQlpbmRleCsrOwoJCQkJCWJyZWFrOyAvLyBHbyB0byBuZXh0IGZlYXR1cmUKCQkJCX0KCQkJfQoJCX0KCQlyZXR1cm4gZmVhdHVyZU9waW5pb25zOwoJfQoKCS8vIEZpcnN0IGludm9rZSBjaGVja0Zvcldhc1BocmFzZVBhdHRlcm4gYW5kIAoJLy8gaWYgaXQgY2Fubm90IGZpbmQgYW4gb3BpbmlvbiBvbmx5IHRoZW4gaW52b2tlIGNoZWNrRm9yT3BpbmlvbkZpcnN0UGF0dGVybgoJcHJpdmF0ZSBzdGF0aWMgaW50IGdldE9waW5pb25PbkZlYXR1cmUoU3RyaW5nIHJldmlldywgU3RyaW5nIGZlYXR1cmUsIFN0cmluZ1tdIHBvc09waW5pb25Xb3JkcywgU3RyaW5nW10gbmVnT3BpbmlvbldvcmRzKSB7CgkJCgkJLy8gQ2FsbCB0aGUgcGF0dGVybiBjaGVja3MKCQlpbnQgcmVzdWx0ID0gY2hlY2tGb3JXYXNQaHJhc2VQYXR0ZXJuKHJldmlldywgZmVhdHVyZSwgcG9zT3BpbmlvbldvcmRzLCBuZWdPcGluaW9uV29yZHMpOwoJCQoJCWlmIChyZXN1bHQgPT0gMCkKCQl7CgkJCXJlc3VsdCA9IGNoZWNrRm9yT3BpbmlvbkZpcnN0UGF0dGVybihyZXZpZXcsIGZlYXR1cmUsIHBvc09waW5pb25Xb3JkcywgbmVnT3BpbmlvbldvcmRzKTsKCQl9CgkJCgkJcmV0dXJuIHJlc3VsdDsKCX0JCgoJLy8gVGlwOiBMb29rIGF0IFN0cmluZyBBUEkgZG9jLiBNZXRob2RzIGxpa2UgaW5kZXhPZiwgbGVuZ3RoLCBzdWJzdHJpbmcoYmVnaW5JbmRleCksIHN0YXJ0c1dpdGggY2FuIGNvbWUgaW50byBwbGF5CgkvLyBSZXR1cm4gMSBpZiBwb3NpdGl2ZSBvcGluaW9uIGZvdW5kLCAtMSBmb3IgbmVnYXRpdmUgb3BpbmlvbiwgMCBmb3Igbm8gb3BpbmlvbgoJLy8gWW91IGNhbiBmaXJzdCBsb29rIGZvciBwb3NpdGl2ZSBvcGluaW9uLiBJZiBub3QgZm91bmQsIG9ubHkgdGhlbiB5b3UgY2FuIGxvb2sgZm9yIG5lZ2F0aXZlIG9waW5pb24KCXByaXZhdGUgc3RhdGljIGludCBjaGVja0Zvcldhc1BocmFzZVBhdHRlcm4oU3RyaW5nIHJldmlldywgU3RyaW5nIGZlYXR1cmUsIFN0cmluZ1tdIHBvc09waW5pb25Xb3JkcywgU3RyaW5nW10gbmVnT3BpbmlvbldvcmRzKSB7CgkJaW50IG9waW5pb24gPSAwOwoJCVN0cmluZyBwYXR0ZXJuID0gZmVhdHVyZSArICIgd2FzICI7IC8vIExldCdzIGRvIHRoaXMgd2l0aG91dCB0b2tlbml6aW5nIHRoZSBzdHJpbmcgYXJvdW5kIHNwYWNlcywgc2luY2Ugd2UgaGF2ZSB0aGlzIHBhdHRlcm4gc3RyaW5nIHByb3ZpZGVkLgoKCQkvLyB5b3VyIGNvZGUKCQlpbnQgaW5kZXggPSByZXZpZXcuaW5kZXhPZihwYXR0ZXJuKTsKCQkKCQkvLyBJZiBwYXR0ZXJuIG1hdGNoZXMKCQlpZiAoaW5kZXggIT0gLTEpIHsKCQkJLy8gTW92ZSBpbmRleCB0byB0aGUgb3BpbmlvbiB3b3JkCgkJCS8vIE5vdGU6IHdpbGwgZ28gb3V0IG9mIGJvdW5kcyBpZiBhdCBlbmQgb2YgcmV2aWV3IHN0cmluZywgYnV0IHdlIHNob3VsZG4ndCBiZSBhdCB0aGUgZW5kIG9mIGEgc3RyaW5nIG1pZC1zZW50ZW5jZQoJCQlpbmRleCArPSBwYXR0ZXJuLmxlbmd0aCgpOyAKCQkJCgkJCS8vIEVycm9yIGNoZWNrCgkJCWlmIChpbmRleCA+PSByZXZpZXcubGVuZ3RoKCkpCgkJCQlyZXR1cm4gMDsgLy8gV2UgaGF2ZSBmb3VuZCBhbiBpbmNvbXBsZXRlIHNlbnRlbmNlIGF0IHRoZSBlbmQgb2YgdGhlIHN0cmluZy4KCQkJCgkJCS8vIFNpbmNlIHdlIGFyZSBub3Qgb3V0IG9mIGJvdW5kcywgZmluZCBvcGluaW9uCgkJCVN0cmluZyBzdWIgPSByZXZpZXcuc3Vic3RyaW5nKGluZGV4KTsKCQkJCgkJCWZvciAoU3RyaW5nIHMgOiBwb3NPcGluaW9uV29yZHMpIHsKCQkJCS8vIElmIHdlIGhhdmUgYSBwb3NpdGl2ZSBvcGluaW9uCgkJCQlpZiAoc3ViLnN0YXJ0c1dpdGgocykpIHsKCQkJCQlvcGluaW9uID0gMTsKCQkJCQlyZXR1cm4gb3BpbmlvbjsKCQkJCX0KCQkJfQoJCQkKCQkJZm9yIChTdHJpbmcgcyA6IG5lZ09waW5pb25Xb3JkcykgewoJCQkJLy8gSWYgd2UgaGF2ZSBhIG5lZ2F0aXZlIG9waW5pb24KCQkJCWlmIChzdWIuc3RhcnRzV2l0aChzKSkgewoJCQkJCW9waW5pb24gPSAtMTsKCQkJCQlyZXR1cm4gb3BpbmlvbjsKCQkJCX0KCQkJfQoJCX0KCQkKCQkvLyBJZiBwYXR0ZXJuIGRvZXNuJ3QgbWF0Y2gsIG9yIG5vIG9waW5pb24gd2FzIGZvdW5kIGFmdGVyIHRoZSBwYXR0ZXJuOgoJCXJldHVybiBvcGluaW9uOyAvLyBzdGlsbCAwIAkKCX0KCQoJcHJpdmF0ZSBzdGF0aWMgaW50IGNoZWNrRm9yT3BpbmlvbkZpcnN0UGF0dGVybihTdHJpbmcgcmV2aWV3LCBTdHJpbmcgZmVhdHVyZSwgU3RyaW5nW10gcG9zT3BpbmlvbldvcmRzLAoJCQlTdHJpbmdbXSBuZWdPcGluaW9uV29yZHMpIHsKCQkvLyBFeHRyYWN0IHNlbnRlbmNlcyBhcyBmZWF0dXJlIG1pZ2h0IGFwcGVhciBtdWx0aXBsZSB0aW1lcy4gCgkJLy8gc3BsaXQoKSB0YWtlcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiBhbmQgIi4iIGlzIGEgc3BlY2lhbCBjaGFyYWN0ZXIgCgkJLy8gZm9yIHJlZ3VsYXIgZXhwcmVzc2lvbi4gU28sIGVzY2FwZSBpdCB0byBtYWtlIGl0IHdvcmshIQoJCVN0cmluZ1tdIHNlbnRlbmNlcyA9IHJldmlldy5zcGxpdCgiXFwuIik7CgkJaW50IG9waW5pb24gPSAwOwoJCQoJCS8vIEZpbmQgcG9zaXRpdmUgYWRqZWN0aXZlICsgZmVhdHVyZSBjb21iaW5hdGlvbgoJCWludCBpbmRleDsKCQlmb3IgKFN0cmluZyBzIDogc2VudGVuY2VzKSB7CgkJCWZvciAoU3RyaW5nIHAgOiBwb3NPcGluaW9uV29yZHMpIHsKCQkJCWluZGV4ID0gcy5pbmRleE9mKGZlYXR1cmUgKyBwKTsKCQkJCS8vIElmIHdlJ3ZlIGZvdW5kIHRoZSBmZWF0dXJlICsgb3BpbmlvbiwgcmV0dXJuCgkJCQlpZiAoaW5kZXggIT0gLTEpIHsKCQkJCQlvcGluaW9uID0gMTsgLy8gVXNlZCBleHBsaWNpdCBzeW50YXggZm9yIHJlYWRhYmlsaXR5LgoJCQkJCXJldHVybiBvcGluaW9uOwoJCQkJfQoJCQl9CgkJfQoJCQoJCS8vIEZpbmQgbmVnYXRpdmUgYWRqZXZ0aXZlICsgZmVhdHVyZSBjb21iaW5hdGlvbgoJCWZvciAoU3RyaW5nIHMgOiBzZW50ZW5jZXMpIHsKCQkJZm9yIChTdHJpbmcgbiA6IG5lZ09waW5pb25Xb3JkcykgewoJCQkJaW5kZXggPSBzLmluZGV4T2YoZmVhdHVyZSArIG4pOwoJCQkJLy8gSWYgd2UndmUgZm91bmQgdGhlIGZlYXR1cmUgKyBvcGluaW9uLCByZXR1cm4KCQkJCWlmIChpbmRleCAhPSAtMSkgewoJCQkJCW9waW5pb24gPSAtMTsgLy8gVXNlZCBleHBsaWNpdCBzeW50YXggZm9yIHJlYWRhYmlsaXR5LgoJCQkJCXJldHVybiBvcGluaW9uOwoJCQkJfQoJCQl9CgkJfQoJCQoJCXJldHVybiBvcGluaW9uOwoJfQoKCXB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpIHsKCQlTdHJpbmcgcmV2aWV3ID0gIkhhdmVuJ3QgYmVlbiBoZXJlIGluIHllYXJzISBGYW50YXN0aWMgc2VydmljZSBhbmQgdGhlIGZvb2Qgd2FzIGRlbGljaW91cyEgRGVmaW5ldGx5IHdpbGwgYmUgYSBmcmVxdWVudCBmbHllciEgRnJhbmNpc2NvIHdhcyB2ZXJ5IGF0dGVudGl2ZSI7CgkJCgkJLy9TdHJpbmcgcmV2aWV3ID0gIlNvcnJ5IE9HLCBidXQgeW91IGp1c3QgbG9zdCBzb21lIGxveWFsIGN1c3RvbWVycy4gSG9ycmlibGUgc2VydmljZSwgbm8gc21pbGUgb3IgZ3JlZXRpbmcganVzdCBhdHRpdHVkZS4gVGhlIGJyZWFkc3RpY2tzIHdlcmUgc3RhbGUgYW5kIGJ1cm50LCBhcHBldGl6ZXIgd2FzIGNvbGQgYW5kIHRoZSBmb29kIGNhbWUgb3V0IGJlZm9yZSB0aGUgc2FsYWQuIjsKCQkKCQlTdHJpbmdbXVtdIGZlYXR1cmVTZXQgPSB7IAoJCSAgICAgICAgeyAiYW1iaWFuY2UiLCAiYW1iaWVuY2UiLCAiYXRtb3NwaGVyZSIsICJkZWNvciIgfSwKCQkJCXsgImRlc3NlcnQiLCAiaWNlIGNyZWFtIiwgImRlc2VydCIgfSwgCgkJCQl7ICJmb29kIiB9LCAKCQkJCXsgInNvdXAiIH0sCgkJCQl7ICJzZXJ2aWNlIiwgIm1hbmFnZW1lbnQiLCAid2FpdGVyIiwgIndhaXRyZXNzIiwgImJhcnRlbmRlciIsICJzdGFmZiIsICJzZXJ2ZXIiIH0gfTsKCQlTdHJpbmdbXSBwb3NPcGluaW9uV29yZHMgPSB7ICJnb29kIiwgImZhbnRhc3RpYyIsICJmcmllbmRseSIsICJncmVhdCIsICJleGNlbGxlbnQiLCAiYW1hemluZyIsICJhd2Vzb21lIiwKCQkJCSJkZWxpY2lvdXMiIH07CgkJU3RyaW5nW10gbmVnT3BpbmlvbldvcmRzID0geyAic2xvdyIsICJiYWQiLCAiaG9ycmlibGUiLCAiYXdmdWwiLCAidW5wcm9mZXNzaW9uYWwiLCAicG9vciIgfTsKCgkJaW50W10gZmVhdHVyZU9waW5pb25zID0gZGV0ZWN0UHJvc0FuZENvbnMocmV2aWV3LCBmZWF0dXJlU2V0LCBwb3NPcGluaW9uV29yZHMsIG5lZ09waW5pb25Xb3Jkcyk7CgkJU3lzdGVtLm91dC5wcmludGxuKCJPcGluaW9ucyBvbiBGZWF0dXJlczogIiArIEFycmF5cy50b1N0cmluZyhmZWF0dXJlT3BpbmlvbnMpKTsKCX0KfQ==