如何获取连字符和尾随子字符串两侧的子字符串?

How to get substrings on both sides of hyphen and trailing substring?

我目前正在开发一个使用特定字符串调用函数的网络应用程序。这是一个示例字符串:

$string = "translate from-to word for translate"

首先我需要验证字符串,它应该像上面的那样$string。我应该如何验证字符串?

然后我需要从$string中提取3个子串。

这是我尝试获取 fromto:

的编码尝试
$found = false;
$source ="";
$target = "";
$next = 3;
$prev = 1;
for($i=0;$i<strlen($string);$i++){
    if($found== false){
        if($string[$i] == "-"){
            $found = true;
            while($string[$i+$prev] != " "){
                $target .= $string[$i+$prev];
                $prev +=1;
            }
            /*$next -=1;
            while($string[$i-$next] != " " && $next > 0){
                $source .= $string[$i-$next];
                $next -=1;
            }*/
        }
    }
}

从那个代码,我只能return-之后包含to$target
我不知道如何得到$source.

请告诉我获得 from 作为 $sourceto 作为 $target 的最快方法。

然后我需要得到word for translatefrom-to之后的所有字符串)。

所以结果应该是

$target = "to";
$source = "from";
$translate = "word for translate";

最后,如果 $string 有两个连字符,比如 translate from-to from-to test-test word for translate,它应该是 return false;

注意 tofrom是随机字符串。

如果我理解正确你的问题,这可以用 regular expression:

<?php
$string = "translate from-to word for translate";
$result = preg_match("/^([\w ]+?) (\w+)-(\w+) ([\w ]+)$/", $string, $matches);
if ($result) {
    print_r($matches);
    $source = $matches[2];
    $target = $matches[3];
    $translate = $matches[4];
} else {
    echo "No match";
}

输出:

Array
(
    [0] => translate from-to word for translate
    [1] => translate
    [2] => from
    [3] => to
    [4] => word for translate
)

这是一个explanation of the regular expression

考虑以下可能的输入字符串:

  • translate from-to word for translate(1 个连字符,无重音符号或非英语字符)
  • translate dari-ke dari-ke word for translate(2 个连字符)
  • translate clé-solution word for translate(1 个连字符,使用重音字符)
  • translate goodbye-さようなら word for translate(1 个连字符,使用日文字符)

像这样的不区分大小写的模式:/^[a-z]+? ([a-z]+)-([a-z]+?) ([a-z ]+)$/i 将按照要求高效地执行前两个示例字符串,但不会执行后两个。

使用 "word character" (\w) 匹配子字符串(而不是不区分大小写的 [a-z])将按预期执行前两个样本,但也允许 0-9_ 作为有效字符。这意味着模式准确性略有下降(这可能对您的项目没有明显影响)。

如果您要翻译的字符串可能超出英文字符范围,使用 "negated character class" 进行匹配会更简单/更宽容。如果你想允许 a-z 以外的字母,如重音字符和其他多字节字符,那么 [^-] 将提供广泛的字符允许(以允许许多不需要的字母为代价)。这里是 a demo of this kind of pattern.

重要的是只为您要随后使用的子字符串编写 "capture groups"。因此,我没有捕获前导子字符串 translate.

list() 是一个方便的 "language construct" 来为数组值分配变量名。请注意,第一个元素(全字符串匹配)未分配给变量。这就是为什么list()的参数以,开头的原因。如果您不想利用 list() 的便利性,那么您可以像这样在三行中手动分配三个变量名称:

$source=$out[1];
$target=$out[2];
$translate=$out[3];

代码:(Demo)

$strings=[
    "translate from-to word for translate",
    "translate dari-ke dari-ke word for translate",
    "translate clé-solution word for translate",
    "translate goodbye-さようなら word for translate"
];

foreach($strings as $string){
    if(preg_match('/^[a-z]+? ([^-]+)-([^-]+?) ([a-z ]+)$/i',$string,$out)){
        list(,$source,$target,$translate)=$out;
        echo "source=$source; target=$target; translate=$translate";
    }else{
        var_export(false);  // $found=false;
    }
    echo "<br>";
}

输出:

source=from; target=to; translate=word for translate
false
source=clé; target=solution; translate=word for translate
source=goodbye; target=さようなら; translate=word for translate

虽然正则表达式提供了一种函数调用更少的更简洁的方法,但这是一种非正则表达式方法:

if(substr_count($string,'-')!=1){
    var_export(false);  // $found=false;
}else{
    $trimmed=ltrim($string,'translate ');
    $array=explode(' ',$trimmed,2);
    list($source,$target)=explode('-',$array[0]);
    $translate=$array[1];
    echo "source=$source; target=$target; translate=$translate";
}