1
votes

Supprimez tous les espaces pour les caractères chinois tout en conservant les espaces nécessaires pour l'anglais dans Python regex

Disons que mon dataframe a une colonne qui est mélangée avec des mots ou des caractères anglais et chinois, je voudrais supprimer tous les espaces entre eux s'ils sont des mots chinois, sinon s'ils sont anglais, gardez un espace uniquement entre les mots:

J'ai trouvé une solution pour supprimer les espaces supplémentaires entre l'anglais d' ici

Out[87]: 
0              Very calm
1    Keen and analytical
2      Rash and careless
3          Always joyful
4                    你好
5                 黑石公司
dtype: object

Code:

Out[87]: 
0              Very calm
1    Keen and analytical
2      Rash and careless
3          Always joyful
4                    你 好
5               黑 石  公 司
dtype: object

En dehors:

regex = re.compile('(?<![a-zA-Z]{2})(?<=[a-zA-Z]{1}) +(?=[a-zA-Z] |.$)')
s.str.replace(regex, '')

Mais comme vous le voyez, cela fonctionne pour l'anglais mais n'a pas supprimé les espaces entre le chinois, comment pourrait-on obtenir un résultat attendu comme suit:

import re
import pandas as pd

s = pd.Series(['V e  r y calm', 'Keen and a n a l y t i c a l',
'R a s h and careless', 'Always joyful', '你 好', '黑 石  公 司', 'FAN     STUD1O', 'beauty face 店  铺'])

Référence: supprimer tous les espaces entre les mots chinois avec regex


4 commentaires

Qu'en est-il des mots à une seule lettre "a" et "I" ?


Merci les gars. Beaucoup de bonnes options.


C'est une bonne question @Bohemian, dans de rares cas, par exemple la XYZ company , le seul espace doit être supprimé et obtenir la XYZ company en fait, mais je ne sais pas comment résoudre ce problème.


J'ai mis à jour de nouveaux éléments pour la série s , il semble qu'aucun de votre solution de travail comme il mélange de l' anglais et chinois. Quelqu'un pourrait-il aider à tester à nouveau?


3 Réponses :


3
votes

Vous pouvez utiliser la propriété Unicode chinoise (enfin, CJK) \p{script=Han} ou \p{Han} .
Cependant, cela ne fonctionne que si le moteur regex prend en charge les expressions régulières Unicode UTS # 18. Le module Python re par défaut ne le fait pas, mais vous pouvez utiliser le moteur de regex alternatif (beaucoup amélioré):

Very calm
Keen and analytical
Rash and careless
Always joyful
你好
黑石公司

Résulte en

import regex as re

rex = r"(?<![a-zA-Z]{2})(?<=[a-zA-Z]{1})[ ]+(?=[a-zA-Z] |.$)|(?<=\p{Han}) +"
test_str = ("V e  r y calm\n"
    "Keen and a n a l y t i c a l\n"
    "R a s h and careless\n"
    "Always joyful\n"
    "你 好\n"
    "黑 石  公 司")
result = re.sub(rex, "", test_str, 0, re.MULTILINE | re.UNICODE)

Démo en ligne (la démo utilise PCRE à des fins de démonstration uniquement)


3 commentaires

rent_name votre code à une colonne rent_name , en utilisant df['rent_name'].replace(re.compile(r"(?<![a-zA-Z]{2})(?<=[a-‌​zA-Z]{1})[ ]+(?=[a-zA-Z] |.$)|(?<=\p{Han}) +", re.MULTILINE | re.UNICODE)) , il renvoie error: bad escape \p , des idées?


Utilisez-vous import regex as re ?


Oui, cela TypeError: replace() missing 1 required positional argument: 'repl' une erreur: TypeError: replace() missing 1 required positional argument: 'repl' . Si test_str est une colonne dans dataframe, comment puis-je utiliser votre code?



2
votes

Utilisez des limites de mots \b pour regarder autour de vous:

['Very calm', 'Keen and analytical', 'Rash and careless', 'Always joyful', '你好', '黑石公司']

Cela correspond aux espaces entre les «caractères de mot» solitaires (délimités par des limites de mots), qui incluent les caractères chinois.

Avant python 3 (et pour java par exemple), \w ne correspond qu'aux lettres anglaises, vous devrez donc ajouter le drapeau unicode (?u) au début de l'expression régulière.


s = ['V e  r y calm', 'Keen and a n a l y t i c a l',
'R a s h and careless', 'Always joyful', '你 好', '黑 石  公 司']
regex = r'(?<=\b\w\b) +(?=\b\w\b)'
res = [re.sub(regex, '', line) for line in s]
print(res)

Production:

(?<=\b\w\b) +(?=\b\w\b)


3 commentaires

Comment pourrais-je votre code pour la colonne s dans dataframe?


Pourquoi avez-vous besoin de (?u) ? Il est activé par défaut dans Python 3.x.


@ WiktorStribiżew Je ne le savais pas. Je suis un novice en python. Réponse simplifiée et note faite sur la version python. Merci



1
votes

Cette regex devrait vous offrir ce que vous voulez. Voir l'extrait de code complet en bas.

0              Very calm
1    Keen and analytical
2      Rash and careless
3          Always joyful
4                     你好
5                   黑石公司
dtype: object

J'ai apporté les modifications suivantes à votre expression régulière ci-dessus: À l'heure actuelle, l'expression régulière correspond essentiellement à tous les espaces qui apparaissent après un mot d'une seule lettre et avant un autre mot à caractère unique.

  1. J'ai ajouté une partie à la fin de l'expression régulière qui sélectionnerait tous les espaces après un caractère chinois (j'ai utilisé la plage unicode [\u4e00-\u9fff] qui couvrirait également le japonais et le coréen.
  2. J'ai changé les espaces dans le regex au caractère des espaces classe \s que nous puissions prendre d' autres entrées comme les onglets.
  3. J'ai également ajouté le drapeau re.UNICODE afin que \s couvre également les espaces Unicode.
import re
import pandas as pd

s = pd.Series(
    [
        "V e  r y calm",
        "Keen and a n a l y t i c a l",
        "R a s h and careless",
        "Always joyful",
        "你 好",
        "黑 石  公 司",
    ]
)

regex = re.compile(
    "((?<![a-zA-Z]{2})(?<=[a-zA-Z]{1})\s+(?=[a-zA-Z]\s|.$)|(?<=[\u4e00-\u9fff]{1})\s+)",
    re.UNICODE,
)
s.str.replace(regex, "")

Production:

regex = re.compile(
    "((?<![a-zA-Z]{2})(?<=[a-zA-Z]{1})\s+(?=[a-zA-Z]\s|.$)|(?<=[\u4e00-\u9fff]{1})\s+)",
    re.UNICODE,
)


2 commentaires

Désolé, votre solution ne semble pas fonctionner pour FAN STUD1O , je pense que nous devons peut-être df['Day'].str.capitalize() puis appliquer votre code?


Je gérerais ce cas avec une expression s.str.replace(re.compile("\s+", re.UNICODE), " ") plus simple qui combine tous les espaces dans une chaîne s.str.replace(re.compile("\s+", re.UNICODE), " ")