2008-10-09 3 views
29

Я искал способ удаления текста из и RTF строки и я нашел следующее регулярное выражение:Регулярное выражение для извлечения текста из 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 }

Любые мысли о том, как улучшить регулярное выражение?

Edit: Более сложная строка, как этот один не работает: {\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 }

ответ

2

Согласно RegexPal, два} 's являются те, выделены жирным шрифтом ниже:

{\ 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 очень хорошо, так что это не может работать во всех случаях, но она работает на вашем примере ...

5

Я использовал это раньше, и он работал на меня:

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

Вы, вероятно, хотите обрезать концы результата, чтобы избавиться от лишних пробелов осталось.

39

В 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, и пропуская группы, которые есть «пункт назначение» указан, и все «игнорируемый "группы ({\* ... }). Я также добавил обработку некоторых специальных символов.

Есть много недостающих функций, чтобы сделать этот полный парсер, но должно быть достаточно для простых документов.

ОБНОВЛЕНО: Этот URL есть этот скрипт обновляется, чтобы работать на Python 3.x:

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

+0

Хороший ответ. \ ~ - неразрывное пространство, поэтому не должно быть char == '~' append u '\ u00a0? – 2011-12-24 23:53:45

+0

Действительно. Обновлено. Благодарю. – 2011-12-25 10:49:31

1

Ни один из ответов не было достаточно, поэтому мое решение было использовать элемент управления RichTextBox (да, даже в не Winform приложение) для извлечения текста из RTF

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

до сих пор мы не нашли хороший ответ на это либо, кроме с помощью элемента управления 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.

4

Похоже, что использование Richtextbox является официальным ответом Microsoft на эту проблему!

3

Я сделал эту вспомогательную функцию для этого в 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 выше. Теперь он удаляет косые черты в конце новых строк за два шага, чтобы избежать более сложного регулярного выражения.
  • .trim() поддерживается только в новых браузерах. Если вам нужно иметь поддержку этим то увидим: Trim string in JavaScript?

EDIT: Я обновил регулярное выражение, чтобы обойти некоторые проблемы, я нашел, так как размещение этого изначально. Я использую это в проекте, см. Здесь в контексте: https://github.com/chrismbarr/LyricConverter/blob/865f17613ee8f43fbeedeba900009051c0aa2826/scripts/parser.js#L26-L37

2

Позднее вкладчик, но регулярное выражение ниже помогло нам с кодом RTF, который мы нашли в нашей БД (мы используем его в RDL через SSRS).

Это выражение удалило его для нашей команды. Хотя это может просто решить наш конкретный RTF, это может быть полезной базой для кого-то. Хотя этот webby невероятно удобен для тестирования в реальном времени.

http://regexpal.com/

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

Надеется, что это помогает, K

0

Вот заявление Oracle SQL, который может лишить RTF из поля Oracle:

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

Это предназначено для передачи данных из Windows, расширенные текстовые элементы управления, а не файлы RTF. ограничения являются:

  • \{ и \} не заменены { и }
  • Верхние и нижние колонтитулы не обрабатываются специально
  • изображения и другие встроенные объекты не обрабатываются специально (понятия не что произойдет, если один из них встречается!)

Он работает, сначала удаляя теги \fcharset и \colourtbl, которые являются поскольку данные следуют за ними до достижения ;. Затем он удаляет все теги \xxx (включая одно необязательное конечное пространство), за которым следуют все символы и }. Это обрабатывает самые простые RTF, такие как то, что вы получаете от богатого текстового элемента управления.

Смежные вопросы