在文档中查找 %string 的变量出现并替换为后缀。当作为 URL 的一部分找到时,%string .prefix 但不是 href

问题描述 投票:0回答:2

我将发送文本到谷歌翻译,但在字符串中,有无法翻译的变量。

所以我必须给它们添加后缀和前缀。

但如果它们位于锚点 href 的 URL 内,则不执行任何操作。

变量可能的格式为:

@foo !bar %foobar {foobar} {foo}.bar !bar_baz %foo-baz

来源:

> Hello Bob @foo <a href="/someurl/!foobar/!bar/word"> Word {foobar} </a> %foo someword !bar_baz

预期结果

> Hello Bob <span class="notranslate">@foo<\span> <a href="/someurl/!foobar/!bar/word"­> Word <span class="notranslate">{foobar}<\span> </a> <span class="notranslate">%foo<\span> someword <span class="notranslate">!bar_baz<\span>

我做了一个非常丑陋的正则表达式来匹配变量并添加后缀和前缀

function PregAddprefixSuffix($text){
      $pregpattern = '/(?<!href=\\")\{[a-zA-Z_0-9]+\}(\.\w+)?|(?<!href=\\")\%[a-zA-Z_0-9\-\w]+|(?<!href=\\")\@[a-zA-Z_0-9\-\w]+|(?<!href=\\")\#[a-zA-Z_0-9\-\w]+|(?<!href=\\")\![a-zA-Z_0-9\-\w]+/';
      $prefix = '<span class="notranslate">';
      $suffix = '</span>';
$result= preg_filter($pregpattern, $prefix.'$0'.$suffix, $text); }

我已经阅读了有关负面反向引用的内容,以尝试过滤掉其中的匹配项。但是如果我理解的话,有一个缺点,即自动回溯-13个字符,下面是我尝试过的 Regx 模式和函数及其缺点。

方法一:

 $p ='/(?<!href=\\")\{[a-zA-Z_0-9]+\}(\.\w+)?|(?<!href=\\")\%[a-zA-Z_0-9\-\w]+|(?<!href=\\")\@[a-zA-Z_0-9\-\w]+|(?<!href=\\")\#[a-zA-Z_0-9\-\w]+|(?<!href=\\")\![a-zA-Z_0-9\-\w]+/';
 preg_filter($p, $prefix.'$0'.$suffix, $text); 

它与 !foobar 匹配非常丑陋,不应该在 href="/someurl/!foobar/word"
专业人士:

  1. 它匹配 !*,%*,@*,{*} 和 {*}.*
  2. 与 preg_filter($p, $prefix.'$0'.$suffix, $text) 一起使用;
  3. 它使用我们的搜索和替换修改中不匹配的部分来呈现输出。

Con:

  1. 非常非常难看,
  2. 在 href 中添加前缀和后缀,这完全破坏了 html 语义。

方法二:

https://www.phpliveregex.com/p/uNB

$p = '/(?:<a.*?\\">)|([\@|\!|\#|\%|\{][a-zA-Z_0-9\-\w]*[\}]?([\}]?[\.][\w]*)?)/';
preg_match_all($p, $input_lines, $output_array)
 print_r($output_array);

这看起来很有希望,它会匹配第 1 组中的所有内容,包括 href,但随后仅匹配 Pro 之外我们想要的变量:

  1. 第 0 组匹配锚点的前半部分(包含 href 的部分),因此 !*、%*、@*、{*} 和 {*}.*
  2. 第 1 组与我们想要的前缀和后缀完全匹配

Con:

  1. 看起来这个解决方案不适用于 preg_filter,它将输入字符串通过修改转移到更改后的输出字符串。 ...

    当前解决方案建议。

  2. 如何从拥有第 2 组数组到拥有修改后的匹配字符串。

  3. 可能使用 PREG_OFFSET_CAPTURE。混合使用 offset + strlen 并考虑匹配的偏移量和长度(prefix.$match.suffix)。
  4. 创建一个在数组中向后移动的函数,获取最后一个匹配的偏移量,然后将其插入到位,然后返回到之前的匹配,在该偏移量处插入 de 修改,并以这种方式遍历数组。

据说使用dom来操作HTML更好,我并不反对。 但是,我如何找到多个通配符变量,例如:

'![a-zA-Z_0-9\-\w]+'
,然后将后缀前缀添加到找到的匹配字符串中,而不是在 href 内匹配?

我正在使用 https://github.com/scotteh/php-dom-wrapper 以便从响应中删除 span 元素

function fixspan($text) {
$doc = new \DOMWrap\Document();
$doc->html($text);
$nodesem = $doc->find('em.notranslate')->contents()->unwrap();
$nodesspan = $doc->find('span.notranslate')->contents()->unwrap();
return $doc->find('body > p')->contents();  } 
php regex dom pcre google-translate
2个回答
1
投票

你可以试试这个:

<a href[^>]*(?:(?:@|!|%|#)\w+|\{\w+\})[^>]*>\K|((?:@|!|%|#)\w+|\{\w+\})

说明:

我已经使用 \K 来否定之前的匹配,所以不需要担心后面的否定。但是 \K 匹配空光标。为此,我提供了替代解决方案。你可以在 php 源代码中找到它。

正则表达式 101 示例

php 源运行它:

$re = '/<a href[^>]*(?:(?:@|!|%|#)\w+|\{\w+\})[^>]*>\K|((?:@|!|%|#)\w+|\{\w+\})/m';
$str = 'Hello Bob @foo <a href="/someurl/!foobar/!bar">Word {foobar} </a> #foo someword #bar
<a href="/abc/d>koramamam</a>';
$subst = '<span class="notranslate">$1<\\\\span>';

$result = preg_replace('/<span class="notranslate"><\\\\span>/m',"",preg_replace($re, $subst, $str));

echo $result;

0
投票

如果您要使用正则表达式,则只需在识别可替换子字符串之前匹配并丢弃开头的

<a>
标记即可。

我发现带有“无翻译”的临时标记有 XY 问题的味道。如果我更好地理解您的实际任务和输入的可变性,我可能会建议使用 DOM 解析器。为了代替更深层次的上下文,我假设您想要进行动态替换。 演示

$pattern = <<<REGEX
/
(?|
  <a .+?>(*SKIP)(*FAIL)
  |
  @([a-z]+)
  |
  !(\w+(?:_\w+)*)
  |
  %(\w+(?:-\w+)*)
  |
  \{([a-z]+)}(\.[a-z]+)?
)
/sx
REGEX;

$lookup = [
    'foo' => 'oof',
    'bar' => 'sand',
    'foobar' => 'FUBAR',
    'foo.bar' => 'nuts',
    'bar_baz' => 'boo',
    'foo-baz' => 'tubas',
];

$input = 'Hello Bob @foo <a href="/someurl/!foobar/!bar/word"> Word {foobar} </a> %foo someword !bar_baz';

echo preg_replace_callback(
         $pattern,
         fn($m) => $lookup[implode(array_slice($m, 1))] ?? $m[0],
         $input
     );

如果我要严格解决发布的问题,这个

preg_replace()
电话就可以了。 演示

$pattern = <<<REGEX
/
(?:
  <a .+?>(*SKIP)(*FAIL)
  |
  @[a-z]+
  |
  !\w+(?:_\w+)*
  |
  %\w+(?:-\w+)*
  |
  \{[a-z]+}(?:\.[a-z]+)?
)
/sx
REGEX;

$input = 'Hello Bob @foo <a href="/someurl/!foobar/!bar/word"> Word {foobar} </a> %foo someword !bar_baz';

echo preg_replace(
         $pattern,
         '<span class="notranslate">$0<\span>',
         $input
     );
© www.soinside.com 2019 - 2024. All rights reserved.