Je cherchais un moyen de supprimer du texte de la chaîne RTF et j'ai trouvé l'expression régulière suivante:
({\\)(.+?)(})|(\\)(.+?)(\b)
Cependant, la chaîne résultante a deux crochets à angle droit "}"
Avant:{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 MS Shell Dlg 2;}{\f1\fnil MS Shell Dlg 2;}} {\colortbl ;\red0\green0\blue0;} {\*\generator Msftedit 5.41.15.1507;}\viewkind4\uc1\pard\tx720\cf1\f0\fs20 can u send me info for the call pls\f1\par }
Après:} can u send me info for the call pls }
Avez-vous des réflexions sur la façon d'améliorer l'expression régulière?
Edit: Une chaîne plus compliquée comme celle-ci ne fonctionne pas: {\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 MS Shell Dlg 2;}} {\colortbl ;\red0\green0\blue0;} {\*\generator Msftedit 5.41.15.1507;}\viewkind4\uc1\pard\tx720\cf1\f0\fs20 HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\test\\myapp\\Apps\\\{3423234-283B-43d2-BCE6-A324B84CC70E\}\par }
Dans RTF, {et} marque un groupe. Les groupes peuvent être imbriqués.\marque le début d'un mot de contrôle. Les mots de contrôle se terminent par un espace ou un caractère non alphabétique. Un mot de contrôle peut avoir un paramètre numérique suivant, sans aucun délimiteur entre les deux. Certains mots de contrôle prennent également des paramètres de texte, séparés par ";". Ces mots de contrôle sont généralement dans leurs propres groupes.
Je pense que j'ai réussi à créer un modèle qui prend en charge la plupart des cas.
\{\*?\\[^{}]+}|[{}]|\\\n?[A-Za-z]+\n?(?:-?\d+)?[ ]?
Il laisse cependant quelques espaces lorsqu'il est exécuté sur votre modèle.
En passant par spécification RTF (une partie), je vois qu'il y a beaucoup d'embûches pour les décapants basés sur des regex purs. Le plus évident est que certains groupes doivent être ignorés (en-têtes, pieds de page, etc.), tandis que d'autres doivent être rendus (formatage).
J'ai écrit un script Python qui devrait fonctionner mieux que mon expression régulière ci-dessus:
def striprtf(text):
pattern = re.compile(r"\\([a-z]{1,32})(-?\d{1,10})?[ ]?|\\'([0-9a-f]{2})|\\([^a-z])|([{}])|[\r\n]+|(.)", re.I)
# control words which specify a "destionation".
destinations = frozenset((
'aftncn','aftnsep','aftnsepc','annotation','atnauthor','atndate','atnicn','atnid',
'atnparent','atnref','atntime','atrfend','atrfstart','author','background',
'bkmkend','bkmkstart','blipuid','buptim','category','colorschememapping',
'colortbl','comment','company','creatim','datafield','datastore','defchp','defpap',
'do','doccomm','docvar','dptxbxtext','ebcend','ebcstart','factoidname','falt',
'fchars','ffdeftext','ffentrymcr','ffexitmcr','ffformat','ffhelptext','ffl',
'ffname','ffstattext','field','file','filetbl','fldinst','fldrslt','fldtype',
'fname','fontemb','fontfile','fonttbl','footer','footerf','footerl','footerr',
'footnote','formfield','ftncn','ftnsep','ftnsepc','g','generator','gridtbl',
'header','headerf','headerl','headerr','hl','hlfr','hlinkbase','hlloc','hlsrc',
'hsv','htmltag','info','keycode','keywords','latentstyles','lchars','levelnumbers',
'leveltext','lfolevel','linkval','list','listlevel','listname','listoverride',
'listoverridetable','listpicture','liststylename','listtable','listtext',
'lsdlockedexcept','macc','maccPr','mailmerge','maln','malnScr','manager','margPr',
'mbar','mbarPr','mbaseJc','mbegChr','mborderBox','mborderBoxPr','mbox','mboxPr',
'mchr','mcount','mctrlPr','md','mdeg','mdegHide','mden','mdiff','mdPr','me',
'mendChr','meqArr','meqArrPr','mf','mfName','mfPr','mfunc','mfuncPr','mgroupChr',
'mgroupChrPr','mgrow','mhideBot','mhideLeft','mhideRight','mhideTop','mhtmltag',
'mlim','mlimloc','mlimlow','mlimlowPr','mlimupp','mlimuppPr','mm','mmaddfieldname',
'mmath','mmathPict','mmathPr','mmaxdist','mmc','mmcJc','mmconnectstr',
'mmconnectstrdata','mmcPr','mmcs','mmdatasource','mmheadersource','mmmailsubject',
'mmodso','mmodsofilter','mmodsofldmpdata','mmodsomappedname','mmodsoname',
'mmodsorecipdata','mmodsosort','mmodsosrc','mmodsotable','mmodsoudl',
'mmodsoudldata','mmodsouniquetag','mmPr','mmquery','mmr','mnary','mnaryPr',
'mnoBreak','mnum','mobjDist','moMath','moMathPara','moMathParaPr','mopEmu',
'mphant','mphantPr','mplcHide','mpos','mr','mrad','mradPr','mrPr','msepChr',
'mshow','mshp','msPre','msPrePr','msSub','msSubPr','msSubSup','msSubSupPr','msSup',
'msSupPr','mstrikeBLTR','mstrikeH','mstrikeTLBR','mstrikeV','msub','msubHide',
'msup','msupHide','mtransp','mtype','mvertJc','mvfmf','mvfml','mvtof','mvtol',
'mzeroAsc','mzeroDesc','mzeroWid','nesttableprops','nextfile','nonesttables',
'objalias','objclass','objdata','object','objname','objsect','objtime','oldcprops',
'oldpprops','oldsprops','oldtprops','oleclsid','operator','panose','password',
'passwordhash','pgp','pgptbl','picprop','pict','pn','pnseclvl','pntext','pntxta',
'pntxtb','printim','private','propname','protend','protstart','protusertbl','pxe',
'result','revtbl','revtim','rsidtbl','rxe','shp','shpgrp','shpinst',
'shppict','shprslt','shptxt','sn','sp','staticval','stylesheet','subject','sv',
'svb','tc','template','themedata','title','txe','ud','upr','userprops',
'wgrffmtfilter','windowcaption','writereservation','writereservhash','xe','xform',
'xmlattrname','xmlattrvalue','xmlclose','xmlname','xmlnstbl',
'xmlopen',
))
# Translation of some special characters.
specialchars = {
'par': '\n',
'sect': '\n\n',
'page': '\n\n',
'line': '\n',
'tab': '\t',
'emdash': u'\u2014',
'endash': u'\u2013',
'emspace': u'\u2003',
'enspace': u'\u2002',
'qmspace': u'\u2005',
'bullet': u'\u2022',
'lquote': u'\u2018',
'rquote': u'\u2019',
'ldblquote': u'\201C',
'rdblquote': u'\u201D',
}
stack = []
ignorable = False # Whether this group (and all inside it) are "ignorable".
ucskip = 1 # Number of ASCII characters to skip after a unicode character.
curskip = 0 # Number of ASCII characters left to skip
out = [] # Output buffer.
for match in pattern.finditer(text):
Word,arg,hex,char,brace,tchar = match.groups()
if brace:
curskip = 0
if brace == '{':
# Push state
stack.append((ucskip,ignorable))
Elif brace == '}':
# Pop state
ucskip,ignorable = stack.pop()
Elif char: # \x (not a letter)
curskip = 0
if char == '~':
if not ignorable:
out.append(u'\xA0')
Elif char in '{}\\':
if not ignorable:
out.append(char)
Elif char == '*':
ignorable = True
Elif Word: # \foo
curskip = 0
if Word in destinations:
ignorable = True
Elif ignorable:
pass
Elif Word in specialchars:
out.append(specialchars[Word])
Elif Word == 'uc':
ucskip = int(arg)
Elif Word == 'u':
c = int(arg)
if c < 0: c += 0x10000
if c > 127: out.append(unichr(c))
else: out.append(chr(c))
curskip = ucskip
Elif hex: # \'xx
if curskip > 0:
curskip -= 1
Elif not ignorable:
c = int(hex,16)
if c > 127: out.append(unichr(c))
else: out.append(chr(c))
Elif tchar:
if curskip > 0:
curskip -= 1
Elif not ignorable:
out.append(tchar)
return ''.join(out)
Il fonctionne en analysant le code RTF, et en ignorant tous les groupes ayant une "destination" spécifiée, et tous les groupes "ignorables" ({\*
...}
). J'ai également ajouté la gestion de certains caractères spéciaux.
Il y a beaucoup de fonctionnalités manquantes pour en faire un analyseur complet, mais cela devrait suffire pour les documents simples.
MISE À JOUR: Cette URL a ce script mis à jour pour s'exécuter sur Python 3.x:
https://Gist.github.com/gilsondev/7c1d2d753ddb522e7bc22511cfb08676
Jusqu'à présent, nous n'avons pas non plus trouvé de bonne réponse à cela, à part utiliser un contrôle RichTextBox:
/// <summary>
/// Strip RichTextFormat from the string
/// </summary>
/// <param name="rtfString">The string to strip RTF from</param>
/// <returns>The string without RTF</returns>
public static string StripRTF(string rtfString)
{
string result = rtfString;
try
{
if (IsRichText(rtfString))
{
// Put body into a RichTextBox so we can strip RTF
using (System.Windows.Forms.RichTextBox rtfTemp = new System.Windows.Forms.RichTextBox())
{
rtfTemp.Rtf = rtfString;
result = rtfTemp.Text;
}
}
else
{
result = rtfString;
}
}
catch
{
throw;
}
return result;
}
/// <summary>
/// Checks testString for RichTextFormat
/// </summary>
/// <param name="testString">The string to check</param>
/// <returns>True if testString is in RichTextFormat</returns>
public static bool IsRichText(string testString)
{
if ((testString != null) &&
(testString.Trim().StartsWith("{\\rtf")))
{
return true;
}
else
{
return false;
}
}
Edit: Ajout de la méthode IsRichText.
Je l'ai utilisé auparavant et cela a fonctionné pour moi:
\\\w+|\{.*?\}|}
Vous voudrez probablement couper les extrémités du résultat pour vous débarrasser des espaces supplémentaires restants.
J'ai créé cette fonction d'aide pour le faire en JavaScript. Jusqu'à présent, cela a bien fonctionné pour la suppression de formatage simple RTF pour moi.
function stripRtf(str){
var basicRtfPattern = /\{\*?\\[^{}]+;}|[{}]|\\[A-Za-z]+\n?(?:-?\d+)?[ ]?/g;
var newLineSlashesPattern = /\\\n/g;
var ctrlCharPattern = /\n\\f[0-9]\s/g;
//Remove RTF Formatting, replace RTF new lines with real line breaks, and remove whitespace
return str
.replace(ctrlCharPattern, "")
.replace(basicRtfPattern, "")
.replace(newLineSlashesPattern, "\n")
.trim();
}
À noter:
.trim()
n'est pris en charge que dans les nouveaux navigateurs. Si vous avez besoin d'un support pour ceux-ci, voyez ceci: Trim string in JavaScript?EDIT: J'ai mis à jour l'expression régulière pour contourner certains problèmes que j'ai trouvés depuis la publication de ce message à l'origine. J'utilise ceci dans un projet, voyez-le en contexte ici: https://github.com/chrismbarr/LyricConverter/blob/865f17613ee8f43fbeedeba900009051c0aa2826/scripts/parser.js#L26-L37
Regex ne résoudra jamais ce problème à 100%, vous avez besoin d'un analyseur. Vérifiez cette implémentation dans CodeProject (c'est en C # cependant): http://www.codeproject.com/Articles/27431/Writing-Your-Own-RTF-Converter
Contributeur tardif mais l'expression régulière ci-dessous nous a aidé avec le code RTF que nous avons trouvé dans notre base de données (nous l'utilisons dans un RDL via SSRS).
Cette expression l'a supprimée pour notre équipe. Bien qu'il puisse simplement résoudre notre RTF spécifique, il peut être une base utile pour quelqu'un. Bien que ce site Web soit incroyablement pratique pour les tests en direct.
{\*?\\.+(;})|\s?\\[A-Za-z0-9]+|\s?{\s?\\[A-Za-z0-9]+\s?|\s?}\s?
J'espère que cela aide, K
Selon RegexPal , les deux} sont ceux en gras ci-dessous:
{\ rtf1\ansi\ansicpg1252\deff0\deflang1033 {\ fonttbl {\ f0\fnil\fcharset0 MS Shell Dlg 2;} {\ f1\fnil MS Shell Dlg 2;} } {\ colortbl;\red0\green0\blue0;} {\ generator Msftedit 5.41.15.1507;}\viewkind4\uc1\pard\tx720\cf1\f0\fs20 pouvez-vous m'envoyer des informations pour l'appel pls\f1\par }
J'ai pu réparer la première accolade en ajoutant un signe plus à l'expression régulière:
({\\)(.+?)(}+)|(\\)(.+?)(\b)
^
plus sign added here
Et pour fixer l'accolade bouclée à la fin, j'ai fait ceci:
({\\)(.+?)(})|(\\)(.+?)(\b)|}$
^
this checks if there is a curly brace at the end
Je ne connais pas très bien le format RTF donc cela pourrait ne pas fonctionner dans tous les cas, mais cela fonctionne sur votre exemple ...
La solution suivante vous permet d'extraire du texte d'une chaîne RTF:
FareRule = Encoding.ASCII.GetString(FareRuleInfoRS.Data);
System.Windows.Forms.RichTextBox rtf = new System.Windows.Forms.RichTextBox();
rtf.Rtf = FareRule;
FareRule = rtf.Text;
Aucune des réponses n'était suffisante, donc ma solution était d'utiliser le contrôle RichTextBox (oui, même dans une application non Winform) pour extraire le texte de RTF
Voici une instruction Oracle SQL qui peut supprimer RTF d'un champ Oracle:
SELECT REGEXP_REPLACE(
REGEXP_REPLACE(
CONTENT,
'\\(fcharset|colortbl)[^;]+;', ''
),
'(\\[^ ]+ ?)|[{}]', ''
) TEXT
FROM EXAMPLE WHERE CONTENT LIKE '{\rtf%';
Il est conçu pour les données des contrôles de texte enrichi de Windows, pas pour les fichiers RTF. Les limitations sont les suivantes:
\{
et \}
ne sont pas remplacés par {
et }
Cela fonctionne en supprimant d'abord le \fcharset
et \colourtbl
tags, qui sont spéciaux car les données les suivent jusqu'à ;
est atteint. Ensuite, il supprime tous les \xxx
balises (y compris un seul espace de fin facultatif), suivies de toutes les {
et }
personnages. Cela gère la plus simple RTF comme ce que vous obtenez du contrôle de texte riche.