nutools/lib/nulib/python/nulib/words.py

238 lines
7.5 KiB
Python

# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
"""Des fonctions pour gérer les phrases et les mots.
"""
__all__ = ('enplural', 'plural',
'splitcc', 'joincc', 'splitus', 'joinus',
's2cc', 'cc2s',
's2us', 'us2s',
'cc2us', 'us2cc',
)
import string, re
from .base import isseq
RE_LAST_LETTER = re.compile(r'([a-zA-Z])[^a-zA-Z]*$')
RE_UPPERCASE = re.compile('[A-Z]')
def __caseof(s, ref):
"""Transformer s en majuscules ou en minuscules suivant la casse de la
dernière lettre de la chaine ref. si ref ne contient aucune lettre,
transformer s en minuscules
"""
mo = RE_LAST_LETTER.search(ref)
if mo is None: return s.lower()
if RE_UPPERCASE.match(mo.group(1)) is not None:
# majuscule
return s.upper()
else:
return s.lower()
RE_CHILD = re.compile(r'(?i)child$')
RE_Y = re.compile(r'(?i)y$')
RE_X = re.compile(r'(?i)x$')
RE_S = re.compile(r'(?i)s$')
def enplural(word):
"""Retourner la forme plurielle du mot anglais word
cas particuliers:
child --> children
*y --> *ies
*x --> *xes
*s --> *ses
sinon, on se contente de rajouter un s
XXX la règle est un peu plus compliquée que cela. l'implémenter
correctement. http://en.wikipedia.org/wiki/English_plural
"""
if RE_CHILD.match(word): return word + __caseof('ren', word)
elif RE_Y.search(word): return word[:-1] + __caseof('ies', word)
elif RE_X.search(word): return word + __caseof('es', word)
elif RE_S.search(word): return word + __caseof('es', word)
else: return word + __caseof('s', word)
RE_PLURAL = re.compile(r'%(?:<([^#<>]*))?(?:>([^#<>]*))?#')
def plural(text, count, format=True):
"""Dans text, remplacer des marqueurs de pluralité par la chaine appropriée
en fonction de la valeur de count.
Un marqueur de pluralité est de la forme %[<sing][>plur]#
Par défaut, sing == '' et plur == 's'
Si count > 1, les marqueurs sont remplacés par plur, sinon ils sont
remplacés par sing.
Si format==True et que text contienne une occurence de %i, le formater avec
text % count.
"""
pos = 0
while True:
mo = RE_PLURAL.search(text, pos)
if mo is None: break
before = text[:mo.start(0)]
after = text[mo.end(0):]
if count > 1:
plural = mo.group(2)
if plural is None: plural = "s"
else:
plural = mo.group(1)
if plural is None: plural = ""
pos = len(before) + len(plural)
text = before + plural + after
if format and text.find("%i") != -1:
text = text % count
return text
def __split_maybe(s, sep=None):
if not isseq(s): s = s.split(sep)
return s
ALL_UPPERCASE_PATTERN = re.compile(r'[A-Z0-9]+$')
UNDERSCORE_PATTERN = re.compile(r'_+')
UPPERCASE_PATTERN = re.compile(r'([A-Z]+)?([^A-Z]*)')
def splitcc(src, plural=False):
"""Spliter des mots écrits en CamelCase. La casse des mots n'est pas
modifiée.
Si plural==True, utiliser enplural pour mettre au pluriel le dernier mot.
e.g.
splitcc('camelCase') --> ['camel', 'Case']
splitcc('URClass') --> ['UR', 'Class']
"""
src = src.strip()
if not src: return []
parts = UPPERCASE_PATTERN.findall(src)
if parts[ - 1] == ('', ''): parts = parts[: - 1]
dests = []
for prefix, suffix in parts:
if prefix == "":
dests.append(suffix)
elif len(prefix) == 1:
dests.append(prefix + suffix)
else:
# len(prefix) > 1
dests.append(prefix[: - 1])
dests.append(prefix[ - 1] + suffix)
if dests and plural: dests[-1] = enplural(dests[-1])
return dests
def joincc(src, firstcap=False, plural=False):
"""Joindre des mots en camelCase. Si les mots sont tout en majuscules, il ne
sont pas modifiés. Sinon, il sont transformés en minuscule, et la première
lettre est capitalisée au besoin.
Si plural==True, utiliser enplural pour mettre au pluriel le dernier mot.
e.g.
joincc('hello world') --> 'helloWorld'
joincc(['hello', 'world']) --> 'helloWorld'
joincc('Hello world') --> 'helloWorld'
joincc('Hello World') --> 'helloWorld'
joincc('HELLO WORLD') --> 'HELLOWORLD'
joincc('Hello world', true) --> 'HelloWorld'
joincc('Hello World', true) --> 'HelloWorld'
joincc('HELLO WORLD', true) --> 'HELLOWORLD'
"""
dests = []
first = True
for s in __split_maybe(src):
if ALL_UPPERCASE_PATTERN.match(s) is None:
if first and not firstcap:
s = s.lower()
else:
s = s.capitalize()
dests.append(s)
first = False
if dests and plural: dests[-1] = enplural(dests[-1])
return ''.join(dests)
def splitus(src, plural=False):
"""Splitter des mots écrits séparés par des '_'. La casse des mots n'est pas
modifiée.
Si plural==True, utiliser enplural pour mettre au pluriel le dernier mot.
e.g.
splitus('under_score') --> ['under', 'score']
splitus('UR_CLASS') --> ['UR', 'CLASS']
"""
src = src.strip()
if not src: return []
dests = UNDERSCORE_PATTERN.split(src)
if dests and plural: dests[-1] = enplural(dests[-1])
return dests
def joinus(src, plural=False):
"""Joindre des mots en les séparant par des '_'. Si les mots sont tout en
majuscules, il ne sont pas modifiés. Sinon, il sont transformés en
minuscule avant d'être séparés par '_'.
Si plural==True, utiliser enplural pour mettre au pluriel le dernier mot.
e.g.
joinus('hello world') --> 'hello_world'
joinus(['hello', 'world']) --> 'hello_world'
joinus('Hello world') --> 'hello_world'
joinus('Hello World') --> 'hello_world'
joinus('HELLO WORLD') --> 'HELLO_WORLD'
"""
dests = []
for s in __split_maybe(src):
if ALL_UPPERCASE_PATTERN.match(s) is None:
s = s.lower()
dests.append(s)
if dests and plural: dests[-1] = enplural(dests[-1])
return '_'.join(dests)
def s2cc(s, firstcap=False, sep=None, plural=False):
"""Transformer une suite de mots séparés par sep en une suite de mots en camelCase.
e.g. s2cc('hello world') --> 'helloWorld'
"""
dests = __split_maybe(s, sep)
if dests and plural: dests[-1] = enplural(dests[-1])
return joincc(dests, firstcap)
def cc2s(cc, sep=None, plural=False):
"""Transformer une suite de mots en camelCase en une suite de mots séparés par sep.
e.g. cc2s('helloWorld') --> 'hello world'
"""
return (sep or ' ').join(map(string.lower, splitcc(cc, plural)))
def s2us(s, sep=None, plural=False):
"""Transformer une suite de mots séparés par sep en une suite de mots séparés par '_'.
e.g. s2cc('hello world') --> 'hello_world'
"""
dests = __split_maybe(s, sep)
if dests and plural: dests[-1] = enplural(dests[-1])
return joinus(dests)
def us2s(us, sep=None, plural=False):
"""Transformer une suite de mots séparés par '_' en une suite de mots séparés par sep.
e.g. cc2s('hello_world') --> 'hello world'
"""
return (sep or ' ').join(map(string.lower, splitus(us, plural)))
def cc2us(cc, plural=False):
"""Transformer une suite de mots en camelCase en une suite de mots séparés par '_'.
e.g. cc2s('helloWorld') --> 'hello_world'
"""
return joinus(splitcc(cc, plural))
def us2cc(us, firstcap=False, plural=False):
"""Transformer une suite de mots séparés par '_' en une suite de mots en camelCase.
e.g. cc2s('hello_world') --> 'helloWorld'
"""
return joincc(splitus(us, plural), firstcap)