summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Smith <git@kismith.co.uk>2014-04-25 10:04:55 (GMT)
committerKevin Smith <git@kismith.co.uk>2014-04-25 15:29:14 (GMT)
commit05f2ef44c2203317a6fc766cd0c5a9a1f241af23 (patch)
treef94e4a10834ae839429b0e793d8ae9daafb626d9 /Swift/Controllers/Chat
parent4c29d43177cb49625f7c6e731c9618b175071141 (diff)
downloadswift-contrib-05f2ef44c2203317a6fc766cd0c5a9a1f241af23.zip
swift-contrib-05f2ef44c2203317a6fc766cd0c5a9a1f241af23.tar.bz2
Make emoticons match only on word boundaries
Change-Id: Ibe6469f8dc60e89ff87f7e65b6c35c5d50858554
Diffstat (limited to 'Swift/Controllers/Chat')
-rw-r--r--Swift/Controllers/Chat/ChatMessageParser.cpp31
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp53
2 files changed, 75 insertions, 9 deletions
diff --git a/Swift/Controllers/Chat/ChatMessageParser.cpp b/Swift/Controllers/Chat/ChatMessageParser.cpp
index ce184ea..698b766 100644
--- a/Swift/Controllers/Chat/ChatMessageParser.cpp
+++ b/Swift/Controllers/Chat/ChatMessageParser.cpp
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2013 Kevin Smith
+ * Copyright (c) 2013-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <Swift/Controllers/Chat/ChatMessageParser.h>
#include <vector>
#include <utility>
@@ -51,43 +51,58 @@ namespace Swift {
}
}
}
std::string regexString;
/* Parse two, emoticons */
foreach (StringPair emoticon, emoticons_) {
- /* Construct a regexp that finds an instance of any of the emoticons inside a group */
- regexString += regexString.empty() ? "(" : "|";
- regexString += Regex::escape(emoticon.first);
+ /* Construct a regexp that finds an instance of any of the emoticons inside a group
+ * at the start or end of the line, or beside whitespace.
+ */
+ regexString += regexString.empty() ? "" : "|";
+ std::string escaped = "(" + Regex::escape(emoticon.first) + ")";
+ regexString += "^" + escaped + "|";
+ regexString += escaped + "$|";
+ regexString += "\\s" + escaped + "|";
+ regexString += escaped + "\\s";
+
}
if (!regexString.empty()) {
- regexString += ")";
+ regexString += "";
boost::regex emoticonRegex(regexString);
ChatWindow::ChatMessage newMessage;
foreach (boost::shared_ptr<ChatWindow::ChatMessagePart> part, parsedMessage.getParts()) {
boost::shared_ptr<ChatWindow::ChatTextMessagePart> textPart;
if ((textPart = boost::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(part))) {
try {
boost::match_results<std::string::const_iterator> match;
const std::string& text = textPart->text;
std::string::const_iterator start = text.begin();
while (regex_search(start, text.end(), match, emoticonRegex)) {
- std::string::const_iterator matchStart = match[0].first;
- std::string::const_iterator matchEnd = match[0].second;
+ int matchIndex = 0;
+ for (matchIndex = 1; matchIndex < static_cast<int>(match.size()); matchIndex++) {
+ if (match[matchIndex].length() > 0) {
+ //This is the matching subgroup
+ break;
+ }
+ }
+ std::string::const_iterator matchStart = match[matchIndex].first;
+ std::string::const_iterator matchEnd = match[matchIndex].second;
if (start != matchStart) {
/* If we're skipping over plain text since the previous emoticon, record it as plain text */
newMessage.append(boost::make_shared<ChatWindow::ChatTextMessagePart>(std::string(start, matchStart)));
}
boost::shared_ptr<ChatWindow::ChatEmoticonMessagePart> emoticonPart = boost::make_shared<ChatWindow::ChatEmoticonMessagePart>();
- std::map<std::string, std::string>::const_iterator emoticonIterator = emoticons_.find(match.str());
+ std::string matchString = match[matchIndex].str();
+ std::map<std::string, std::string>::const_iterator emoticonIterator = emoticons_.find(matchString);
assert (emoticonIterator != emoticons_.end());
const StringPair& emoticon = *emoticonIterator;
emoticonPart->imagePath = emoticon.second;
emoticonPart->alternativeText = emoticon.first;
newMessage.append(emoticonPart);
start = matchEnd;
}
if (start != text.end()) {
/* If there's plain text after the last emoticon, record it */
diff --git a/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
index 44d7834..0a14303 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
@@ -1,26 +1,31 @@
/*
- * Copyright (c) 2013 Kevin Smith
+ * Copyright (c) 2013-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <hippomocks.h>
#include <Swift/Controllers/Chat/ChatMessageParser.h>
using namespace Swift;
class ChatMessageParserTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ChatMessageParserTest);
CPPUNIT_TEST(testFullBody);
+ CPPUNIT_TEST(testOneEmoticon);
+ CPPUNIT_TEST(testBareEmoticon);
+ CPPUNIT_TEST(testHiddenEmoticon);
+ CPPUNIT_TEST(testEndlineEmoticon);
+ CPPUNIT_TEST(testBoundedEmoticons);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {
smile1_ = ":)";
smile1Path_ = "/blah/smile1.png";
smile2_ = ":(";
smile2Path_ = "/blah/smile2.jpg";
emoticons_[smile1_] = smile1Path_;
@@ -32,18 +37,19 @@ public:
}
void assertText(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
boost::shared_ptr<ChatWindow::ChatTextMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(result.getParts()[index]);
CPPUNIT_ASSERT_EQUAL(text, part->text);
}
void assertEmoticon(const ChatWindow::ChatMessage& result, size_t index, const std::string& text, const std::string& path) {
boost::shared_ptr<ChatWindow::ChatEmoticonMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatEmoticonMessagePart>(result.getParts()[index]);
+ CPPUNIT_ASSERT(!!part);
CPPUNIT_ASSERT_EQUAL(text, part->alternativeText);
CPPUNIT_ASSERT_EQUAL(path, part->imagePath);
}
void assertURL(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
boost::shared_ptr<ChatWindow::ChatURIMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatURIMessagePart>(result.getParts()[index]);
CPPUNIT_ASSERT_EQUAL(text, part->target);
}
@@ -56,18 +62,63 @@ public:
assertText(result, 3, " ");
assertEmoticon(result, 4, smile1_, smile1Path_);
assertText(result, 5, " ");
assertURL(result, 6, "http://wonderland.lit/blah");
assertText(result, 7, " ");
assertURL(result, 8, "http://denmark.lit");
assertText(result, 9, " boom boom");
}
+ void testOneEmoticon() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody(" :) ");
+ assertText(result, 0, " ");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+ assertText(result, 2, " ");
+ }
+
+
+ void testBareEmoticon() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody(":)");
+ assertEmoticon(result, 0, smile1_, smile1Path_);
+ }
+
+ void testHiddenEmoticon() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody("b:)a");
+ assertText(result, 0, "b:)a");
+ }
+
+ void testEndlineEmoticon() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody("Lazy:)");
+ assertText(result, 0, "Lazy");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+ }
+
+ void testBoundedEmoticons() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody(":)Lazy:(");
+ assertEmoticon(result, 0, smile1_, smile1Path_);
+ assertText(result, 1, "Lazy");
+ assertEmoticon(result, 2, smile2_, smile2Path_);
+ }
+
+ void testEmoticonParenthesis() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody("(Like this :))");
+ assertText(result, 0, "(Like this ");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+ assertText(result, 2, ")");
+ }
+
+
private:
std::map<std::string, std::string> emoticons_;
std::string smile1_;
std::string smile1Path_;
std::string smile2_;
std::string smile2Path_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(ChatMessageParserTest);