我不确定这是否是一个简单的问题,但到目前为止我一直找不到答案。我正在尝试编写一个正则表达式,该表达式将.docx文件拆开,并将所有<w:tab />
标记替换为<w:ind />
标记,因为<w:tab>
标记在转换为html时似乎无法正确保留制表符。我在PHP中工作,到目前为止,我还没有成功地编写出一个正则表达式来正确地完成我需要它做的事情。
问题是,我不能在这里只运行一个简单的查找和替换函数。我必须移除<w:tab />
标签,并在最近的打开和关闭<w:rPr></w:rPr>
标签内注入<w:ind />
标签。
示例XML字符串如下所示:
<w:p w14:paraId="2679030C" w14:textId="4E6FFA99" w:rsidR="00ED4314" w:rsidRPr="00254747" w:rsidRDefault="00ED4314" w:rsidP="00322270">
<w:pPr>
<w:pStyle w:val="NoSpacing" />
<w:spacing w:line="480" w:lineRule="auto" />
<w:jc w:val="both" />
<w:rPr>
<w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:cs="Times New Roman" />
<w:sz w:val="24" />
<w:szCs w:val="24" />
</w:rPr>
</w:pPr>
<w:r w:rsidRPr="00254747">
<w:rPr>
<w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:cs="Times New Roman" />
<w:sz w:val="24" />
<w:szCs w:val="24" />
</w:rPr>
<w:tab />
<w:t>SOME text</w:t>
</w:r>
<w:r w:rsidR="0003297C">
<w:rPr>
<w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:cs="Times New Roman" />
<w:sz w:val="24" />
<w:szCs w:val="24" />
</w:rPr>
<w:t>SOME more text</w:t>
</w:r>
<w:r w:rsidRPr="00254747">
<w:rPr>
<w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:cs="Times New Roman" />
<w:sz w:val="24" />
<w:szCs w:val="24" />
</w:rPr>
<w:t>EVEN more text</w:t>
</w:r>
</w:p>
因此,<w:tab/>
的每个实例都需要删除,然后我需要追溯到以前的<w:rPr>
标签,并在其中注入一个<w:ind />
标签
到目前为止,我有以下几种:
$content = preg_replace("/<w:rPr>(.*?)<'/w:rPr>(.*?)<w:tab'/>/", "<w:rPr><w:ind w:firstLine='"720'"/>$1</w:rPr>$2", $content);
这种方法是可行的,但问题是我认为搜索过于全球化。尽管我指定它不是贪婪的,但它返回给我的结果比它们应该得到的内容多得多。有人能提出一个优化的方法吗?提前感谢!
我认为您将非贪婪与正则表达式"知道"在找到更多标签之前停止混淆—但它做不到。如果的意思是禁止</w:rPr>
和<w:tab/>
之间的标签,那么这应该大致有效:
/<w:rPr>(.*?)<'/w:rPr>([^<]*?)<w:tab'/>/
^^^^
这被称为否定字符类,并且匹配不是<
—因此在找到CCD_ 13之前不会消耗任何其他标签。
编辑为了回应您的澄清,即在找到<w:tab/>
之前允许除<w:rPr>
之外的所有标签,您需要使用否定前瞻断言,因为正如您正确理解的那样,否定字符类只排除字符,而不包括字符串。
/<w:rPr>(.*?)<'/w:rPr>((?:(?!<w:rPr>).)*?)<w:tab'/>/
^^^^^^^^^^^^^^^^
如果(?:xyz)
令人困惑,请忽略它—这只是一种获取括号而不是的方式来捕获—不过,对于量词,*
,我需要括号。这里的重要部分是(?!xyz)
,它被称为负面前瞻断言(顺便说一句,它也是一个非捕获组(—如果向前看并且没有找到"xyz",则匹配;所以,我们上面要做的是:(1(向前看,(2(如果是而不是<w:rPr>
,那么(3(匹配一个字符.
,以及(4(重复—直到找到CCD_ 21。