正则表达式:查找字符串中不在文本区域内的换行符

3

嘿呀,我正在寻找一个正则表达式,它可以让我基本上用任何东西(例如“xxx”)替换换行符,但仅当换行符不在textarea标记内时才能替换。

例如,以下内容:

<strong>abcd
efg</strong>
<textarea>curious
george
</textarea>
<span>happy</span>

Would become:

<strong>abcdxxxefg</strong>xxx<textarea>curious
geroge
</textarea>xxx<span>happy</span>

有人知道我应该从哪里开始吗?我有点茫然无措 :( 非常感谢任何可能的帮助。


1
为了完整起见,将<pre>标签添加到同一列表中:换行符在其中也有意义。 - Pekka
我一直在尝试使用lookaround来确定它是否有效,但到目前为止,我只发现了恰好相反的情况:替换文本区域内的EOL:(?<=]*?>.*)[\r\n]+(?=.*)您可以使用此方法对textarea中的EOL进行“编码”,处理其他EOL,然后恢复已编码的EOL。 - Stijn Sanders
1
在上述建议的基础上添加: (?<=<(textarea|pre|code|xmp)[^>]?>.)[\r\n]+(?=.*</\1>) - Stijn Sanders
@Stijn:这些正则表达式需要无限制的、可变长度的后顾断言,而 PHP 不支持。 - Alan Moore
4个回答

3

我明白了,但你可能不会喜欢它。;)

$result = preg_replace(
  '~[\r\n]++(?=(?>[^<]++|<(?!/?textarea\b))*+(?!</textarea\b))~',
  'XYZ', $source);

匹配换行符后,前瞻扫描向前,消耗任何不是左尖括号的字符,或者任何不是标签开头的左尖括号。当它用完这些字符之后,它看到的下一件事情必须是这些标签之一或字符串的结尾。如果它是一个标签,那么意味着找到了textarea元素内的换行符,因此匹配失败,并且该换行符不被替换。我在下面提供了一个扩展版本,您可以在ideone上查看其运行情况。如果您真的想要处理那些其他标签,可以进行调整。但是听起来您需要的是HTML最小化程序(或缩小程序);有很多这样的程序可用。
  $re=<<<EOT
~
[\r\n]++
(?=
  (?>
    [^<]++            # not left angle brackets, or
  |
    <(?!/?textarea\b) # bracket if not for TA tag (opening or closing)
  )*+
  (?!</textarea\b)    # first TA tag found must be opening, not closing
)
~x
EOT;

1

如果您仍然想使用正则表达式,可以尝试这个方法 - 在特殊标签内转义换行符,删除换行符,然后取消转义:

<?php //5.3 syntax here

//Regex matches everything within textarea, pre or code tags
$str = preg_replace_callback('#<(?P<tag>textarea|pre|code)[^>]*?>.*</(?P=tag)>#sim',
    function ($matches) { 
         //and then replaces every newline by some escape sequence
         return str_replace("\n", "%ESCAPED_NEWLINE%", $matches[0]);
    }, $str);
//after all we can safely remove newlines
//and then replace escape sequences by newlines
$str = str_replace(array("\n", "%ESCAPED_NEWLINE%"), array('', "\n"), $str);

我会趁着等待他的回复尝试一下这个。虽然有点困惑,但如果可能的话,我还是愿意避免使用正则表达式。'状态机'是什么意思? - onassar
好的,我已经添加了更多的注释。你到底是哪里困惑了?谷歌一下状态机。基本上,你需要在迭代文本时保持某种“状态”,在这种情况下,状态是回答“我是否在文本区域标签内”的问题。根据该状态,您将替换或保留换行符。 - Andrew

0
为什么要使用正则表达式呢?为什么不使用一个非常简单的状态机来完成它呢?遍历字符串,查找开放的<textarea>标签,并在其中寻找关闭标签。当遇到换行符时,根据当前是否在<textarea>中进行转换或不转换。

能否再解释一下?可以用伪代码吗?我对此有些困惑。:( - onassar
1
哈哈,状态机。我闻到了一个刚上完逻辑电路课的大学生的味道。去年我也上过那门课 =)状态机是硬件术语。在软件术语中,你会说它是一个带有开关或标志的迭代(或递归)循环。 - stevendesu
我正在攻读纯数学博士学位,从未上过电子或编程课。我将其称为“状态机”,因为我以前见过它被称为这个名字。 - Hammerite

0

你正在解析HTML。你不能使用正则表达式来解析HTML。


你的理解还不够准确。在一般情况下,是的,你不能这样做,因为php实现的正则表达式中没有递归。但在这种特殊情况下,你可以这样做,因为你不能有嵌套的文本区域。 - Andrew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接