计算两个字符串间的levenshteinDistance
@param string $string1
@param string $string2
@param int $costReplace 定义替换次数
@param string $encoding
@return mixed
771662
public static function levenshteinDistance($string1, $string2,  $costReplace = 1, $encoding = 'UTF-8')
    {
        $mbStringToArrayFunc = function ($string) use ($encoding)
        {
            $arrayResult = [];
            while ($iLen = mb_strlen($string, $encoding)) {
                array_push($arrayResult, mb_substr($string, 0, 1, $encoding));
                $string = mb_substr($string, 1, $iLen, $encoding);
            }
            return $arrayResult;
        };

        $countSameLetter = 0;
        $d = [];
        $mbLen1 = mb_strlen($string1, $encoding);
        $mbLen2 = mb_strlen($string2, $encoding);

        $mbStr1 = $mbStringToArrayFunc($string1, $encoding);
        $mbStr2 = $mbStringToArrayFunc($string2, $encoding);

        $maxCount = count($mbStr1) > count($mbStr2) ? count($mbStr1) : count($mbStr2);

        for ($i1 = 0; $i1 <= $mbLen1; $i1++) {
            $d[$i1] = [];
            $d[$i1][0] = $i1;
        }

        for ($i2 = 0; $i2 <= $mbLen2; $i2++) {
            $d[0][$i2] = $i2;
        }

        for ($i1 = 1; $i1 <= $mbLen1; $i1++) {
            for ($i2 = 1; $i2 <= $mbLen2; $i2++) {
                // $cost = ($str1[$i1 - 1] == $str2[$i2 - 1]) ? 0 : 1;
                if ($mbStr1[$i1 - 1] === $mbStr2[$i2 - 1]) {
                    $cost = 0;
                    $countSameLetter++;
                } else {
                    $cost = $costReplace; //替换
                }
                $d[$i1][$i2] = min($d[$i1 - 1][$i2] + 1, //插入
                    $d[$i1][$i2 - 1] + 1, //删除
                    $d[$i1 - 1][$i2 - 1] + $cost);
            }
        }

        $percent  = round(($maxCount - $d[$mbLen1][$mbLen2]) / $maxCount, 2);

        //return $d[$mbLen1][$mbLen2];
        return ['distance' => $d[$mbLen1][$mbLen2], 'count_same_letter' => $countSameLetter, 'percent' => $percent];
    }
929084
public function join($str1 = null, $str2 = null)
    {
        if (is_null($str1)) {
            $str1 = $this->number();
        }
        if (is_null($str2)) {
            $str2 = $this->vn();
        }

        return $str1 . $this->vnSeparator . $str2;
    }
789567
public static function ensureLeft($string, $search, $encoding = null)
    {
        if (static::startsWith($string, $search, true, $encoding)) {
            return $string;
        }

        return $search . $string;
    }
410770
public static function shift(string &$str, string $encoding = null)
    {
        $encoding = $encoding ?: mb_internal_encoding();

        $first = mb_substr($str, 0, 1, $encoding);
        $str = mb_substr($str, 1, null, $encoding);

        return $first;
    }
1348605
public static function compareBaseStrings($string1, $string2)
    {
    	if ( $string1 == $string2 ) return true;

    	$out2 = "";
    	$out1 = "";
        $chars = 0;
    	$oops = false;
        for($i=0; $i<strlen($string1)&&$i<strlen($string2); $i++) {
    		if ( $oops || $string1[$i] == $string2[$i] ) {
    			$out1 = $out1 . $string1[$i];
    			$out2 = $out2 . $string2[$i];
    		} else {
    			$out1 = $out1 . ' ->' . $string1[$i] .'<- ';
    			$out2 = $out2 . ' ->' . $string2[$i] .'<- ';
    			$oops = true;
    		}
    		$chars = $chars + 1;
    		if ( $chars > 79 ) {
    			$out1 .= "\n";
    			$out2 .= "\n";
    			$chars = 0;
    		}
    	}
    	if ( $i < strlen($string1) ) {
    		$out2 = $out2 . ' -> truncated ';
    		for($i=0; $i<strlen($string1); $i++) {
    			$out1 = $out1 . $string1[$i];
    			$chars = $chars + 1;
    			if ( $chars > 79 ) {
    				$out1 .= "\n";
    				$chars = 0;
    			}
    		}
    	}

    	if ( $i < strlen($string2) ) {
    		$out1 = $out1 . ' -> truncated ';
    		for($i=0; $i<strlen($string2); $i++) {
    			$out2 = $out2 . $string2[$i];
    			$chars = $chars + 2;
    			if ( $chars > 79 ) {
    				$out2 .= "\n";
    				$chars = 0;
    			}
    		}
    	}
    	return $out1 . "\n-------------\n" . $out2 . "\n";
    }
1269408
public static function sub($str, $start, $length = null, $encoding = null) {
        $encoding or $encoding = \Fuel::$encoding;
        // substr functions don't parse null correctly
        $length = is_null($length) ? (function_exists('mb_substr') ? mb_strlen($str, $encoding) : strlen($str)) - $start : $length;
        return function_exists('mb_substr') ? mb_substr($str, $start, $length, $encoding) : substr($str, $start, $length);
    }
67988
public static function getDistanceBetweenXPaths($xpath1, $xpath2)
    {
        if (strlen($xpath1) > strlen($xpath2))
        {
            $diff = substr($xpath1, strlen($xpath2));
        }
        else
        {
            $diff = substr($xpath2, strlen($xpath1));
        }

        return count(explode('/', $diff));
    }
449566
public function compareLength($stringOne, $stringTwo) {
    $lengthOne = strlen($stringOne);
    $lengthTwo = strlen($stringTwo);
    if ($lengthOne > $lengthTwo) {
      return -1;
    } elseif ($lengthOne < $lengthTwo) {
      return 1;
    } else {
      return strcmp($stringOne, $stringTwo);
    }
  }
326370
public static function endsWith($value, string $search, string $encoding = 'UTF-8'): bool
    {
        if (!static::isStringCastable($value)) {
            return false;
        }

        $searchlen = (int) mb_strlen($search, $encoding);
        $length = (int) mb_strlen((string) $value, $encoding);
        $end = mb_substr((string) $value, $length - $searchlen, $searchlen, $encoding);

        return $search === $end;
    }
313421
function substringPlacement( $startOffset, $endOffset, $totalStringLength )
    {
        $leftText = false;
        $rightText = false;

        if ( $startOffset > 0 )
            $leftText = true;

        if ( $endOffset < $totalStringLength-1 )
            $rightText = true;

        return array( 'hasTextLeft' => $leftText,
                      'hasTextRight' => $rightText );
    }
302547
private function compareLong($value1, $value2, $operator)
    {
        switch ($operator) {
            case FieldExpression::EQUALS:
                return $value1 === $value2;

            case FieldExpression::NOT_EQUALS:
                return $value1 !== $value2;

            case FieldExpression::GT:
                return $value1 > $value2;

            case FieldExpression::LT:
                return $value1 < $value2;
        }

        $errMsg = 'unknown field operator';
        throw new InvalidArgumentException($errMsg);
    }
1141325
public static function compareAmounts($price1, $price2)
    {
        //====================================================================//
        // Compare Price
        if ($price1["base"]) {
            if (abs($price1["ttc"] - $price2["ttc"]) > 1E-6) {
                return false;
            }
        } else {
            if (abs($price1["ht"] - $price2["ht"]) > 1E-6) {
                return false;
            }
        }
        //====================================================================//
        // Compare VAT
        if (abs($price1["vat"] - $price2["vat"]) > 1E-6) {
            return false;
        }
        //====================================================================//
        // Compare Currency If Set on Both Sides
        if (empty($price1["code"]) || empty($price2["code"])) {
            return true;
        }
        if ($price1["code"] !== $price2["code"]) {
            return false;
        }
        //====================================================================//
        // Prices Are Identical
        return true;
    }
269762
public static function strcasecmp($string1, $string2): int
    {
        if (self::$collator instanceof Collator) {
            return self::$collator->compare($string1, $string2);
        }

        return strcmp(self::strtolower($string1), self::strtolower($string2));
    }
520773
public int compare(String string2, int maxDistance) {
        switch (algorithm) {
            case Damerau: return DamerauLevenshteinDistance(string2, maxDistance);
        }
        throw new IllegalArgumentException("unknown DistanceAlgorithm");
    }
411833
private function performCompare($image1, $image2)
    {
        $result = $image1->compareImages($image2, Imagick::METRIC_MEANSQUAREERROR);
        return $result[1];
    }
919572
public function stringReplace($string, $replace)
    {
        if ($this->_mappingsChanged) {
            $this->_generateMappings();
        }

        if (strpos("\n", $string)) {
            throw new Exception('string must not contain \n');
        }
        if ($replace != "" && strpos("\n", $replace)) {
            throw new Exception('replace must not contain \n');
        }

        $adjustOffsets = array();
        $pos = 0;
        $str = $this->_fileContents;
        $offset = 0;
        $lineOffset = 0;
        while (($pos = strpos($str, $string, $pos)) !== false) {
            $line = substr_count(substr($str, 0, $pos), "\n") + 1;
            if (!isset($adjustOffsets[$line])) {
                //first in line
                $lineOffset = 0;
            }
            $this->_fileContents = substr($this->_fileContents, 0, $pos + $offset).$replace.substr($this->_fileContents, $pos + $offset + strlen($string));
            $offset += strlen($replace) - strlen($string);
            $lineOffset += strlen($replace) - strlen($string);
            $column = $pos - strrpos(substr($str, 0, $pos), "\n") + 1; //strrpos can return false for first line which will subtract 0 (=false)
            $adjustOffsets[$line][] = array(
                'column' => $column,
                'absoluteOffset' => $offset,
                'lineOffset' => $lineOffset,
                'offset' => strlen($replace) - strlen($string),
                'replacedLength' => strlen($string)
            );
            $pos = $pos + strlen($string);
        }

        $mappings = $this->getMappings();
        $this->_mappingsChanged = true;
        $this->_mappings = array();
        foreach ($mappings as $mappingIndex=>$mapping) {
            if (isset($adjustOffsets[$mapping['generatedLine']])) {
                foreach (array_reverse($adjustOffsets[$mapping['generatedLine']], true) as $offsIndex=>$offs) {
                    if ($mapping['generatedColumn'] > $offs['column']) {
                        if ($mapping['generatedColumn'] < $offs['column']-1+$offs['replacedLength']) {
                            //mapping inside replaced test, remove
                            continue 2;
                        } else {
                            $mapping['generatedColumn'] += $offs['lineOffset'];
                            break;
                        }
                    }
                }
            }
            $this->_mappings[] = $mapping;
        }
    }
74048
public static function removeLeft($string, $search, $encoding = null)
    {
        if ($string === '') {
            return '';
        }

        if ($search === '') {
            return $string;
        }

        $encoding = $encoding === null ? mb_internal_encoding() : $encoding;

        if (!static::startsWith($string, $search, true, $encoding)) {
            return $string;
        }

        return Mbstring::substr($string, Mbstring::strlen($search), null, $encoding);
    }