我一直在寻找一种从RTF字符串中删除文本的方法,我找到了以下正则表达式:
({\\)(.+?)(})|(\\)(.+?)(\b)
但是,结果字符串有两个直角括号“}”
之前: {\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 }
有关如何改进正则表达式的任何想法?
修改:更复杂的字符串(如此字符串)不起作用:{\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 }
答案 0 :(得分:53)
在RTF中,{和}标记一个组。组可以嵌套。 \标记控制字的开头。控制字以空格或非字母字符结尾。控制字可以包含数字参数,其间没有任何分隔符。一些控制字也采用文本参数,用';'分隔。这些控制词通常在他们自己的小组中。
我想我已经设法制定了一个照顾大多数情况的模式。
\{\*?\\[^{}]+}|[{}]|\\\n?[A-Za-z]+\n?(?:-?\d+)?[ ]?
虽然在你的模式上运行时会留下一些空格。
通过RTF specification(其中一些),我发现纯正的基于正则表达式的脱衣舞娘存在很多陷阱。最明显的一个是应该忽略一些组(页眉,页脚等),而其他组则应该被渲染(格式化)。
我编写了一个Python脚本,它应该比上面的正则表达式更好:
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)
它的工作原理是解析RTF代码,并跳过指定了“目标”的所有组,以及所有“可忽略”的组({\*
... }
)。我还添加了一些特殊字符的处理。
缺少很多功能可以使它成为一个完整的解析器,但对于简单的文档应该足够了。
更新:此网址已更新此脚本以在Python 3.x上运行:
https://gist.github.com/gilsondev/7c1d2d753ddb522e7bc22511cfb08676
答案 1 :(得分:7)
到目前为止,除了使用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方法。
答案 2 :(得分:6)
我之前使用过它,它对我有用:
\\\w+|\{.*?\}|}
您可能希望修剪结果的末尾以消除剩余的额外空格。
答案 3 :(得分:4)
我使用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();
}
注意:
.trim()
仅在较新的浏览器中受支持。如果您需要支持这些,请参阅:Trim string in JavaScript? 答案 4 :(得分:3)
正则表达式永远不会100%解决这个问题,你需要一个解析器。 在CodeProject中检查这个实现(虽然它在C#中): http://www.codeproject.com/Articles/27431/Writing-Your-Own-RTF-Converter
答案 5 :(得分:2)
根据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 } 强>
我能够通过在正则表达式中添加一个加号来修复第一个大括号:
({\\)(.+?)(}+)|(\\)(.+?)(\b)
^
plus sign added here
为了修复大括号,我做了这个:
({\\)(.+?)(})|(\\)(.+?)(\b)|}$
^
this checks if there is a curly brace at the end
我不太了解RTF格式,所以这可能不适用于所有情况,但它适用于您的示例......
答案 6 :(得分:2)
后期贡献者,但下面的正则表达式帮助我们使用我们在数据库中找到的RTF代码(我们通过SSRS在RDL中使用它)。
此表达式已将其删除给我们的团队。虽然它可能只是解决我们的特定RTF,但它可能是一个有用的基础。虽然这个webby对于实时测试来说非常方便。
{\*?\\.+(;})|\s?\\[A-Za-z0-9]+|\s?{\s?\\[A-Za-z0-9]+\s?|\s?}\s?
希望这有帮助, ķ
答案 7 :(得分:1)
没有一个答案是足够的,所以我的解决方案是使用RichTextBox控件(是的,即使在非Winform应用程序中)从RTF中提取文本
答案 8 :(得分:1)
以下解决方案允许您从RTF字符串中提取文本:
FareRule = Encoding.ASCII.GetString(FareRuleInfoRS.Data);
System.Windows.Forms.RichTextBox rtf = new System.Windows.Forms.RichTextBox();
rtf.Rtf = FareRule;
FareRule = rtf.Text;
答案 9 :(得分:0)
这是一个可以从Oracle字段中删除RTF的Oracle SQL语句:
SELECT REGEXP_REPLACE(
REGEXP_REPLACE(
CONTENT,
'\\(fcharset|colortbl)[^;]+;', ''
),
'(\\[^ ]+ ?)|[{}]', ''
) TEXT
FROM EXAMPLE WHERE CONTENT LIKE '{\rtf%';
这是专为来自Windows富文本控件而非RTF文件的数据而设计的。 限制是:
\{
和\}
未被{
和}
首先删除\fcharset
和\colourtbl
标记,这些标记很特殊,因为数据会跟随它们,直到达到;
为止。然后,它会删除所有\xxx
标记(包括单个可选的尾随空格),然后删除所有{
和}
个字符。这可以处理大多数简单的RTF,例如您从富文本控件获得的内容。