正则expression式从RTFstring中提取文本

我正在寻找一种方法来删除和RTFstring的文本,我发现了以下正则expression式:

({\\)(.+?)(})|(\\)(.+?)(\b) 

但是由此产生的string有两个右尖括号“}”

之前: {\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 }

之后: } can u send me info for the call pls }

任何想法如何改善正则expression式?

编辑:像这样一个更复杂的string不起作用: {\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 }

在RTF中,{和}标记一个组。 组可以嵌套。 \标记一个控制字的开始。 控制字以空格或非字母字符结束。 一个控制字可以有一个数字参数,其间没有任何分隔符。 一些控制字也采用以';'分隔的文本参数。 这些控制字通常在他们自己的群体中。

我想我已经设法制定了一个照顾大多数情况的模式。

 \{\*?\\[^{}]+}|[{}]|\\\n?[A-Za-z]+\n?(?:-?\d+)?[ ]? 

当你的模式运行时,它会留下一些空格。


通过RTF规范 (其中的一些),我发现纯正则expression式剥离器存在很多缺陷。 最明显的是应该忽略一些组(页眉,页脚等),而其他组则应该呈现(格式化)。

我已经写了一个Python脚本,应该比我上面的正则expression式更好:

 def striprtf(text): pattern = re.compile(r"\\([az]{1,32})(-?\d{1,10})?[ ]?|\\'([0-9a-f]{2})|\\([^az])|([{}])|[\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) 

它通过parsingRTF代码,并跳过指定了“目标”的所有组以及所有“可忽略”组( {\*} )。 我还加了一些特殊字符的处理。

有很多function缺less使这个完整的parsing器,但应该足够简单的文件。

更新:此url已更新此脚本以在Python 3.x上运行:

https://gist.github.com/gilsondev/7c1d2d753ddb522e7bc22511cfb08676

到目前为止,我们还没有find一个好的答案,除了使用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; } } 

编辑:添加了IsRichText方法。

我以前用过这个,对我也有用:

 \\\w+|\{.*?\}|} 

您可能需要修剪结果的末尾以除去剩余的空格。

它看起来像使用Richtextbox是微软的这个问题的正式答案!

我做了这个帮助函数在JavaScript中做到这一点。 到目前为止,这对于简单的RTF格式删除工作很好。

 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(); } 

注意:

  • 我稍微修改了上面@Markus Jarderot写的正则expression式。 它现在在两个步骤中删除新行末尾的斜线,以避免更复杂的正则expression式。
  • .trim()仅在较新的浏览器中受支持。 如果你需要支持这些,那么看看这个: 在JavaScript中修剪string?

编辑:我已经更新了正则expression式来解决一些问题,我发现自最初张贴这个。 我在一个项目中使用这个,在上下文中看到它: https : //github.com/chrismbarr/LyricConverter/blob/865f17613ee8f43fbeedeba900009051c0aa2826/scripts/parser.js#L26-L37

据RegexPal ,这两个是下面的粗体:

{\ 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可以给我发信息给pls \ f1 \ par }

我能够通过给正则expression式添加一个加号来修复第一个大括号:

 ({\\)(.+?)(}+)|(\\)(.+?)(\b) ^ plus sign added here 

为了修复花括号,我做了这个:

 ({\\)(.+?)(})|(\\)(.+?)(\b)|}$ ^ this checks if there is a curly brace at the end 

我不太了解RTF格式,所以这可能不适用于所有情况,但它适用于您的示例…

正则expression式不会100%解决这个问题,你需要一个parsing器。 在CodeProject中检查这个实现(它是用C#): http : //www.codeproject.com/Articles/27431/Writing-Your-Own-RTF-Converter

后期的贡献者,但下面的正则expression式帮助我们在我们的数据库中find的RTF代码(我们通过SSRS在RDL中使用它)。

这个expression式为我们的团队删除了它。 虽然它可能只是解决我们特定的RTF,但它可能是一个有用的基础。 虽然这webby是现场testing令人难以置信的方便。

http://regexpal.com/

 {\*?\\.+(;})|\s?\\[A-Za-z0-9]+|\s?{\s?\\[A-Za-z0-9]+\s?|\s?}\s? 

希望这有助于,K

没有答案是足够的,所以我的解决scheme是使用RichTextBox控件(是的,即使在非Winform应用程序)从RTF中提取文本

  FareRule = Encoding.ASCII.GetString(FareRuleInfoRS.Data); System.Windows.Forms.RichTextBox rtf = new System.Windows.Forms.RichTextBox(); rtf.Rtf = FareRule; FareRule = rtf.Text; 

这是一个可以从Oracle字段中去除RTF的Oracle SQL语句:

 SELECT REGEXP_REPLACE( REGEXP_REPLACE( CONTENT, '\\(fcharset|colortbl)[^;]+;', '' ), '(\\[^ ]+ ?)|[{}]', '' ) TEXT FROM EXAMPLE WHERE CONTENT LIKE '{\rtf%'; 

这是为来自Windows富文本控件而不是RTF文件的数据而devise的。 限制是:

  • \{\}不会被replace为{}
  • 页眉和页脚不是专门处理的
  • 图像和其他embedded式对象不是专门处理的(不知道如果遇到其中一个会发生什么事情!)

它通过首先删除\fcharset\colourtbl标签,这是特殊的,因为数据跟随他们直到; 到达了。 然后删除所有的\xxx标签(包括一个可选的尾部空格),其后是所有的{}字符。 这可以处理最简单的RTF,例如从富文本控件中获得的内容。