我将发送文本到谷歌翻译,但在字符串中,有无法翻译的变量。
所以我必须给它们添加后缀和前缀。
但如果它们位于锚点 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"
专业人士:
Con:
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 之外我们想要的变量:
Con:
看起来这个解决方案不适用于 preg_filter,它将输入字符串通过修改转移到更改后的输出字符串。 ...
如何从拥有第 2 组数组到拥有修改后的匹配字符串。
据说使用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(); }
你可以试试这个:
<a href[^>]*(?:(?:@|!|%|#)\w+|\{\w+\})[^>]*>\K|((?:@|!|%|#)\w+|\{\w+\})
说明:
我已经使用 \K 来否定之前的匹配,所以不需要担心后面的否定。但是 \K 匹配空光标。为此,我提供了替代解决方案。你可以在 php 源代码中找到它。
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;
如果您要使用正则表达式,则只需在识别可替换子字符串之前匹配并丢弃开头的
<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
);