String: allow multi-character inputs in "ord" and "unicodename"

This allows them to support emoji ZWJ sequences, which render like one character but are actually multiple.
This commit is contained in:
James Lu 2022-10-05 18:40:03 -07:00 committed by Val Lorentz
parent 35bf599856
commit b1cfb87e71
2 changed files with 29 additions and 18 deletions

View File

@ -51,13 +51,13 @@ import multiprocessing
class String(callbacks.Plugin): class String(callbacks.Plugin):
"""Provides useful commands for manipulating characters and strings.""" """Provides useful commands for manipulating characters and strings."""
def ord(self, irc, msg, args, letter): def ord(self, irc, msg, args, s):
"""<letter> """<string>
Returns the unicode codepoint of <letter>. Returns the unicode codepoint of characters in <string>.
""" """
irc.reply(str(ord(letter))) irc.replies([str(ord(char)) for char in s])
ord = wrap(ord, ['letter']) ord = wrap(ord, ['text'])
def chr(self, irc, msg, args, i): def chr(self, irc, msg, args, i):
"""<number> """<number>
@ -70,17 +70,20 @@ class String(callbacks.Plugin):
irc.error(_('That number doesn\'t map to a unicode character.')) irc.error(_('That number doesn\'t map to a unicode character.'))
chr = wrap(chr, ['int']) chr = wrap(chr, ['int'])
def unicodename(self, irc, msg, args, character): def unicodename(self, irc, msg, args, s):
"""<character> """<string>
Returns the name of the given unicode <character>.""" Returns the name of characters in <string>.
if len(character) != 1: This will error if any character is not a valid Unicode character."""
irc.errorInvalid('character', character) replies = []
for idx, char in enumerate(s):
try: try:
irc.reply(unicodedata.name(character)) replies.append(unicodedata.name(char))
except ValueError: except ValueError:
irc.error(_('No name found for this character.')) irc.error(_('No name found for character %r at position %d.') %
unicodename = wrap(unicodename, ['something']) (char, idx), Raise=True)
irc.replies(replies)
unicodename = wrap(unicodename, ['text'])
def unicodesearch(self, irc, msg, args, name): def unicodesearch(self, irc, msg, args, name):
"""<name> """<name>

View File

@ -103,13 +103,21 @@ class StringTestCase(PluginTestCase):
for c in map(chr, range(256)): for c in map(chr, range(256)):
i = ord(c) i = ord(c)
self.assertResponse('ord %s' % utils.str.dqrepr(c), str(i)) self.assertResponse('ord %s' % utils.str.dqrepr(c), str(i))
self.assertResponse('ord é', '233')
self.assertResponse('ord 🆒', '127378')
self.assertResponse('ord 🇦🇶', '127462 and 127478')
def testUnicode(self): def testUnicode(self):
self.assertResponse('unicodename ☃', 'SNOWMAN') self.assertResponse('unicodename ☃', 'SNOWMAN')
self.assertResponse('unicodesearch SNOWMAN', '') self.assertResponse('unicodesearch SNOWMAN', '')
#self.assertResponse('unicodename ?', self.assertResponse('unicodename ?', 'QUESTION MARK')
# 'No name found for this character.')
# multi-char strings and ZWJ sequences
self.assertResponse('unicodename :O', 'COLON and LATIN CAPITAL LETTER O')
self.assertResponse('unicodename 🤷‍♂️', 'SHRUG, ZERO WIDTH JOINER, MALE SIGN, and VARIATION SELECTOR-16')
self.assertError('unicodename "\\uFFFF"')
self.assertError('unicodename "!@#\\uFFFF$"')
self.assertResponse('unicodesearch FOO', self.assertResponse('unicodesearch FOO',
'Error: No character found with this name.') 'Error: No character found with this name.')