有没有一种PHP类可以清理内容?

5

我一直在尝试使用一系列正则表达式和PHP函数 preg_replace 来编写 PHP 代码。

我的主要目的是通过一些方式来整理内容,例如确保一个句子的开头有大写字母;逗号后面有一个空格等。

以下是我试图实现的一些整理示例:

// Remove any spaces around slashes
$content_replacements_from[] = "/\s*\/\s*/";
$content_replacements_to[] = "/";

// Remove any new lines or tabs
$content_replacements_from[] = "/[\r\n\t]/";
$content_replacements_to[] = " ";

// Remove any extra spaces
$content_replacements_from[] = "/\s{2,}/";
$content_replacements_to[] = " ";

// Tidy up joined full stops
$content_replacements_from[] = "/([a-zA-Z]{1})\s*[\.]{1}\s*([^(jpeg|jpg|png|pdf|gif|doc|xls|docx|xlsx|ppt|pptx|html|php|htm)]{1})/";
$content_replacements_to[] = "$1. $2";

// Tidy up joined commas
$content_replacements_from[] = "/([a-zA-Z0-9]{1})\s*[\,]{1}\s*([a-zA-Z0-9]{1})/";
$content_replacements_to[] = "$1, $2";

// Tidy up joined exclamation marks
$content_replacements_from[] = "/([a-zA-Z0-9]{1})\s*[\!]{1}\s*([a-zA-Z0-9]{1})/";
$content_replacements_to[] = "$1! $2";

// Tidy up joined question marks
$content_replacements_from[] = "/([a-zA-Z0-9]{1})\s*[\?]{1}\s*([a-zA-Z0-9]{1})/";
$content_replacements_to[] = "$1? $2";

// Tidy up joined semi colons
$content_replacements_from[] = "/([a-zA-Z0-9]{1})\s*[\;]{1}\s*([a-zA-Z0-9]{1})/";
$content_replacements_to[] = "$1; $2";

// Tidy up joined colons
$content_replacements_from[] = "/([a-zA-Z0-9]{1})\s*[\:]{1}\s*([a-zA-Z0-9]{1})/";
$content_replacements_to[] = "$1: $2";

// Tidy up fluid ounces
$content_replacements_from[] = "/[Ff]{1}[Ll]{1}.?\s?[Oo]{1}[Zz]{1}/";
$content_replacements_to[] = "fl oz";

// Tidy up rpm
$content_replacements_from[] = "/[Rr]{1}[Pp]{1}[Mm]{1}/";
$content_replacements_to[] = "rpm";

// Tidy up UK
$content_replacements_from[] = "/[Uu]{1}[Kk]{1}/";
$content_replacements_to[] = "UK";

// Tidy up Maxi-sense
$content_replacements_from[] = "/[Mm]{1}axi[\s\-]?[Ss]{1}ense/";
$content_replacements_to[] = "maxi-sense";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Mm]{1}axi[\s\-]?[Ss]{1}ense/";
$content_replacements_to[] = ". Maxi-sense";
$content_replacements_from[] = "/^[Mm]{1}axi[\s\-]?[Ss]{1}ense/";
$content_replacements_to[] = "Maxi-sense";

// Tidy up Side-by-side
$content_replacements_from[] = "/[Ss]{1}ide[\s\-]?[Bb]{1}y[\s\-]?[Ss]{1}ide/";
$content_replacements_to[] = "side-by-side";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Ss]{1}ide[\s\-]?[Bb]{1}y[\s\-]?[Ss]{1}ide/";
$content_replacements_to[] = ". Side-by-side";
$content_replacements_from[] = "/^[Ss]{1}ide[\s\-]?[Bb]{1}y[\s\-]?[Ss]{1}ide/";
$content_replacements_to[] = "Side-by-side";

// Tidy up extra large
$content_replacements_from[] = "/[Xx]{1}[Ll]{l}/";
$content_replacements_to[] = "extra large";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Xx]{1}[Ll]{l}/";
$content_replacements_to[] = "Extra large";
$content_replacements_from[] = "/^[Xx]{1}[Ll]{l}/";
$content_replacements_to[] = "Extra large";

// Tidy up D-radius
$content_replacements_from[] = "/[Dd]{1}[\s\-]?[Rr]{1}adius/";
$content_replacements_to[] = "D-radius";

// Tidy up A-rate
$content_replacements_from[] = "/[Aa]{1}[\s\-]?[Rr]{1}ate/";
$content_replacements_to[] = "A-rate";

// Tidy up In-column
$content_replacements_from[] = "/[Ii]{1}n[\s\-]?[Cc]{1}olum[n]?/";
$content_replacements_to[] = "in-column";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Ii]{1}n[\s\-]?[Cc]{1}olum[n]?/";
$content_replacements_to[] = "In-column";
$content_replacements_from[] = "/^[Ii]{1}n[\s\-]?[Cc]{1}olum[n]?/";
$content_replacements_to[] = "In-column";

// Tidy up kW
$content_replacements_from[] = "/[Kk]{1}[Ww]{1}/";
$content_replacements_to[] = "kW";

// Tidy up Built-in
$content_replacements_from[] = "/[Bb]{1}uilt[\s\-]?[Ii]{1}n/";
$content_replacements_to[] = "built-in";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Bb]{1}uilt[\s\-]?[Ii]{1}n/";
$content_replacements_to[] = "Built-in";
$content_replacements_from[] = "/^[Bb]{1}uilt[\s\-]?[Ii]{1}n/";
$content_replacements_to[] = "Built-in";

// Tidy up Built-under
$content_replacements_from[] = "/[Bb]{1}uilt[\s\-]?[Uu]{1}nder/";
$content_replacements_to[] = "built-under";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Bb]{1}uilt[\s\-]?[Uu]{1}nder/";
$content_replacements_to[] = "Built-under";
$content_replacements_from[] = "/^[Bb]{1}uilt[\s\-]?[Uu]{1}nder/";
$content_replacements_to[] = "Built-under";

// Tidy up Under-counter
$content_replacements_from[] = "/[Uu]{1}nder[\s\-]?[Cc]{1}ounter/";
$content_replacements_to[] = "under-counter";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Uu]{1}nder[\s\-]?[Cc]{1}ounter/";
$content_replacements_to[] = "Under-counter";
$content_replacements_from[] = "/^[Uu]{1}nder[\s\-]?[Cc]{1}ounter/";
$content_replacements_to[] = "Under-counter";

// Tidy up Under-cabinet
$content_replacements_from[] = "/[Uu]{1}nder[\s\-]?[Cc]{1}abinet/";
$content_replacements_to[] = "under-cabinet";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Uu]{1}nder[\s\-]?[Cc]{1}abinet/";
$content_replacements_to[] = "Under-cabinet";
$content_replacements_from[] = "/^[Uu]{1}nder[\s\-]?[Cc]{1}abinet/";
$content_replacements_to[] = "Under-cabinet";

// Tidy up integrated
$content_replacements_from[] = "/([a-zA-Z0-9]{1})[\s]{1}[\-]{1}[Ii]{1}ntegrated/";
$content_replacements_to[] = "$1-integrated";

// Tidy up Semi-integrated
$content_replacements_from[] = "/[Ss]{1}emi[\s\-]?[Ii]{1}ntegrated/";
$content_replacements_to[] = "semi-integrated";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Ss]{1}emi[\s\-]?[Ii]{1}ntegrated/";
$content_replacements_to[] = "Semi-integrated";
$content_replacements_from[] = "/^[Ss]{1}emi[\s\-]?[Ii]{1}ntegrated/";
$content_replacements_to[] = "Semi-integrated";

// Tidy up Fully-integrated
$content_replacements_from[] = "/[Ff]{1}ully[\s\-]?[Ii]{1}ntegrated/";
$content_replacements_to[] = "fully-integrated";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Ff]{1}ully[\s\-]?[Ii]{1}ntegrated/";
$content_replacements_to[] = "Fully-integrated";
$content_replacements_from[] = "/^[Ff]{1}ully[\s\-]?[Ii]{1}ntegrated/";
$content_replacements_to[] = "Fully-integrated";

// Tidy up Semi-automatic
$content_replacements_from[] = "/[Ss]{1}emi[\s\-]?[Aa]{1}utomatic/";
$content_replacements_to[] = "semi-automatic";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Ss]{1}emi[\s\-]?[Aa]{1}utomatic/";
$content_replacements_to[] = "Semi-automatic";
$content_replacements_from[] = "/^[Ss]{1}emi[\s\-]?[Aa]{1}utomatic/";
$content_replacements_to[] = "Semi-automatic";

// Tidy up Fully-automatic
$content_replacements_from[] = "/[Ff]{1}ully[\s\-]?[Aa]{1}utomatic/";
$content_replacements_to[] = "fully-automatic";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Ff]{1}ully[\s\-]?[Aa]{1}utomatic/";
$content_replacements_to[] = "Fully-automatic";
$content_replacements_from[] = "/^[Ff]{1}ully[\s\-]?[Aa]{1}utomatic/";
$content_replacements_to[] = "Fully-automatic";

// Tidy up Pull-out
$content_replacements_from[] = "/[Pp]{1}ull[\s\-]?[Oo]{1}ut/";
$content_replacements_to[] = "pull-out";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Pp]{1}ull[\s\-]?[Oo]{1}ut/";
$content_replacements_to[] = "Pull-out";
$content_replacements_from[] = "/^[Pp]{1}ull[\s\-]?[Oo]{1}ut/";
$content_replacements_to[] = "Pull-out";

// Tidy up including
$content_replacements_from[] = "/\s[Ii]{1}nc[l]?[\.]?\s/";
$content_replacements_to[] = " including ";

// Tidy up use
$content_replacements_from[] = "/\s[Uu]{1}se\s/";
$content_replacements_to[] = " use ";

// Tidy up ?-piece
$content_replacements_from[] = "/([2345TtYy]{1})[\s\-]?[Pp]{1}iece/";
$content_replacements_to[] = "$1-piece";

// Tidy up ?-spout
$content_replacements_from[] = "/([Cc]{1})[\s\-]?[Ss]{1}pout/";
$content_replacements_to[] = "$1-spout";

// Tidy up ?-end
$content_replacements_from[] = "/([Cc]{1})[\s\-]?[Ee]{1}nd/";
$content_replacements_to[] = "$1-end";

// Tidy up Brushed Steel
$content_replacements_from[] = "/[Bb]{1}[\-\/]{1}[Ss]{1}teel/";
$content_replacements_to[] = "brushed steel";

// Tidy up Stainless Steel
$content_replacements_from[] = "/[Ss]{1}[\-\/]{1}[Ss]{1}teel/";
$content_replacements_to[] = "stainless steel";

// Tidy up Silk Steel
$content_replacements_from[] = "/[Ss]{1}ilk[\s]?[Ss]{1}teel/";
$content_replacements_to[] = "silk steel";

// Remove trade marks
$content_replacements_from[] = "/™/";
$content_replacements_to[] = "";

// Replace long dashes
$content_replacements_from[] = "/–/";
$content_replacements_to[] = "-";

// Replace single quotes
$content_replacements_from[] = "/’/";
$content_replacements_to[] = "'";
$content_replacements_from[] = "/`/";
$content_replacements_to[] = "'";

// Tidy up m
$content_replacements_from[] = "/[\s]?[Mm]{1}etre/";
$content_replacements_to[] = "m";

// Tidy up m3
$content_replacements_from[] = "/([0-9]{1})[\s]?[Mm]{1}3/";
$content_replacements_to[] = "$1m³";
$content_replacements_from[] = "/\&sup3\;/";
$content_replacements_to[] = html_entity_decode("³");

// Tidy up to in between numbers
$content_replacements_from[] = "/([0-9]{1})[\s]?to[\s]?([0-9]{1})/";
$content_replacements_to[] = "$1 - $2";

// Tidy up per hour
$content_replacements_from[] = "/\s[Aa]{1}nd\s[Hh]{1}[Rr]?$/";
$content_replacements_to[] = "ph";

// Tidy up l
$content_replacements_from[] = "/[\s]?[Ll]{1}itre/";
$content_replacements_to[] = "l";

// Tidy up -in
$content_replacements_from[] = "/\-[Ii]{1}n/";
$content_replacements_to[] = "-in";

// Tidy up plus
$content_replacements_from[] = "/\s[Pp]{1}lus\s/";
$content_replacements_to[] = " plus ";

// Tidy up including
$content_replacements_from[] = "/\s[Ii]{1}ncluding\s/";
$content_replacements_to[] = " including ";

// Tidy up including
$content_replacements_from[] = "/[Ii]{1}nc\s/";
$content_replacements_to[] = "Including "; 

// Tidy up Push/pull
$content_replacements_from[] = "/[Pp]{1}ush\/[Pp]{1}ull/";
$content_replacements_to[] = "push/pull";
$content_replacements_from[] = "/[\.|\!|\?]{1}\s{1}[Pp]{1}ush\/[Pp]{1}ull/";
$content_replacements_to[] = "Push/pull";
$content_replacements_from[] = "/^[Pp]{1}ush\/[Pp]{1}ull/";
$content_replacements_to[] = "Push/pull";

// Tidy up +
$content_replacements_from[] = "/\s\+\s/";
$content_replacements_to[] = " and ";

// Tidy up *
$content_replacements_from[] = "/\*/";
$content_replacements_to[] = "";

// Tidy up with
$content_replacements_from[] = "/\s[Ww]{1}ith\s/";
$content_replacements_to[] = " with ";

// Tidy up without
$content_replacements_from[] = "/\s[Ww]{1}ithout\s/";
$content_replacements_to[] = " without ";

// Tidy up in
$content_replacements_from[] = "/\s[Ii]{1}n\s/";
$content_replacements_to[] = " in ";

// Tidy up of
$content_replacements_from[] = "/\s[Oo]{1}f\s/";
$content_replacements_to[] = " of ";

// Tidy up for
$content_replacements_from[] = "/\s[Ff]{1}or\s/";
$content_replacements_to[] = " for ";

// Tidy up or
$content_replacements_from[] = "/\s[Oo]{1}r\s/";
$content_replacements_to[] = " or ";

// Tidy up and
$content_replacements_from[] = "/\s[Aa]{1}nd\s/";
$content_replacements_to[] = " and ";

// Tidy up to
$content_replacements_from[] = "/\s[Tt]{1}o\s/";
$content_replacements_to[] = " to ";

// Tidy up too
$content_replacements_from[] = "/\s[Tt]{1}oo\s/";
$content_replacements_to[] = " too ";

// Tidy up &
$content_replacements_from[] = "/\s&\s/";
$content_replacements_to[] = " and ";

// Tidy up &
$content_replacements_from[] = "/\s&\s/";
$content_replacements_to[] = " and ";

// Tidy up mm
$content_replacements_from[] = "/M[Mm]{1}/";
$content_replacements_to[] = "mm";

// Tidy up ize to ise
$content_replacements_from[] = "/([a-zA-Z]{2})ize{1}/";
$content_replacements_to[] = "$1ise";

// Tidy up izer to iser
$content_replacements_from[] = "/([a-zA-Z]{2})izer{1}/";
$content_replacements_to[] = "$1iser";

// Tidy up yze to yse
$content_replacements_from[] = "/([a-zA-Z]{2})yze{1}/";
$content_replacements_to[] = "$1yse";

// Tidy up ization to isation
$content_replacements_from[] = "/([a-zA-Z]{2})ization{1}/";
$content_replacements_to[] = "$1isation";

// Tidy up times symbol
$content_replacements_from[] = "/([0-9]{1})\s*[Xx]\s*([0-9A-Za-z]{1})/";
$content_replacements_to[] = "$1 × $2";

// Tidy up times symbol
$content_replacements_from[] = "/\&times\;/";
$content_replacements_to[] = html_entity_decode("×");

// Tidy up inches
$content_replacements_from[] = "/([0-9]{1})\s*[Ii]{1}nches/";
$content_replacements_to[] = "$1\"";

// Tidy up inch
$content_replacements_from[] = "/([0-9]{1})\s*[Ii]{1}nch/";
$content_replacements_to[] = "$1\"";

// Make the replacements
$content = preg_replace($content_replacements_from, $content_replacements_to, $content);

这显然很复杂且冗长。

是否有人知道更好的方法或者知道一个能够完成此任务的类?

如果可以的话,我还想将其应用到HTML内容中。


嗨 Paul,谢谢你的提示。那是一个很好的观点。 - Adam Stacey
你的正则表达式技术上能正常工作,还是你对它们也有问题? - hakre
4个回答

7

正则表达式非常适合进行文本搜索和替换。你所拥有的这些表达式显示出它们还有改进的空间。但是我的回答不是关于优化它们的,相反我建议开始构建自己的一套 StringCleaner 工具,可以做不同的事情,但都具有相同的接口:

interface StringCleaner
{
    public function clean($string);
}

除此之外,对于HTML,我的一个想法是创建一个FilterIterator,以便提供对所有文本节点的访问,这样它们就可以更轻松地使用任何标准清理器进行更改。

为了一次应用多个StringCleaner(并创建这些的集合),我使用了组合模式(通过扩展SplObjectStore)作为自己的StringCleaner

不带类定义的示例:

$cleanerTrim = new TrimCleaner();

$cleanerBasics = new RegexCleaner();

// Remove any spaces around slashes
$cleanerBasics->addRule('\s*\/\s*', '/');

// Remove any new lines or tabs
$cleanerBasics->addRule('[\r\n\t]', ' ');

// Tidy up joined full stops
$cleanerBasics->addRule('(\w+)\.(?!jpeg|jpg|png|pdf|gif|doc|xls|docx|xlsx|ppt|pptx|html|php|htm)(\w+)', '$1. $2');

// Remove any extra spaces
$cleanerBasics->addRule('\s{2,}', ' ');

// Remove single spaces
$cleanerBasics->addRule('^\s$', '');

$cleanerInches = new RegexCleaner();

// Tidy up inches
$cleanerInches->addRule('([0-9])\s*[Ii]nches', '$1"');


$cleaner = new CleanerComposite();
$cleaner->attach($cleanerBasics);
$cleaner->attach($cleanerInches);
$cleaner->attach($cleanerTrim);


$htmlString = <<<HTML
<html>
  <head>
    <title>
        hello world.hello earth.
    </title>
  </head>
  <body>
<table><tr><td>test. 
</td></tr></table>
     <h1>Get it 1 more time.</h1>
     <p>When 12 inches were not enough;      hickup.</p>

  </body>
</html>
HTML;


// load HTML
$dom = new DOMDocument();
$dom->preserveWhiteSpace = FALSE;
$dom->loadHTML($htmlString);

// create XPath
$xpath = new DomXPath($dom);

$it = new DOMTextWhiteSpaceFilter($xpath->query('//text()'));
foreach($it as $node)
{
    $node->data = $cleaner->clean($node->data);
}

// remove whitespace only nodes
$it = new DOMTextWhiteSpaceFilter($xpath->query('//text()'), DOMTextWhiteSpaceFilter::WHITESPACE);
foreach($it as $node)
{
    $node->parentNode->removeChild($node);
}

$dom->formatOutput = true;
echo $dom->saveHTML();

如示例所示,当您将复杂性隐藏到具体的StringCleaner对象中时,您可以开始创建更多动态规则。这可以通过添加更多操作不同于正则表达式的StringCleaner类型来扩展,其中使用trim的非常简单的示例在TrimCleaner中给出。
但是,正则表达式也非常强大。如RegexCleaner所示,我已经将每个正则表达式定界符移动到类本身中,因此当您定义规则时,无需一遍又一遍地输入它们。这只是另一个简单的例子,在其中将替换封装到自己的类中,并为操作定义了定义接口,可以简化事情。 完整示例

抱歉,Hakre,我离线了一段时间。谢谢你对此问题的详细回答。非常感谢。 - Adam Stacey

2

可能有比使用大量正则表达式更好的方法,但如果没有其他更好的工具,我会使用PHP正则表达式来完成这项任务。

易读性和易维护性几乎总是比速度更重要。preg_replace需要两个单独的字符串或数组来匹配和替换,但我们可以通过重新排列数据来处理它。因此,我建议采用以下更易读的格式:

$content_replacements = array(array('From' => "/pattern 1/", 'To' => "$1 $2"),
                              array('From' => "/pattern 2/", 'To' => "$1,$2."));

它有一个很大的优点,如果你忘记了一个“from”或“to”,你的模式和替换不会失去同步。

然后,要运行所有这些操作,您可以使用一个循环:

   foreach ($content_replacements as $replacement)
   {
      $content = preg_replace($replacement['From'], $replacement['To'], $content);
   }

嗨 Paul,谢谢你。我一定会用这个的。但是你认为我是在看错东西了吗?我已经考虑过了,你觉得我应该寻找一个语法检查或拼写检查类型的类吗?你知道有哪些吗? - Adam Stacey
@AdamStacey 你好,从我快速查看手册的结果来看,我认为Enchant可以用于逐字逐句的拼写检查。但是对于你特定的替换需求,仅查看单词可能不够。我认为一定有更好的解决方案 - 如果没有更好的解决方案出现,我会在一天内提供悬赏。 - Paul

2

我认为你想要的第一件事是找到一个关于正则表达式的好参考资料,并复习哪些字符需要在字符类(方括号:[])内外进行转义。然后,通过删除{1}并在有意义时使用大小写不敏感匹配('//i'),来清理你的正则表达式。接着,我包含了一些代码可以用来整合一些大写规则,希望对你有所帮助。

// capitalize first word of each sentence
function tidy_sentences($str){
    $tokens = array();
    foreach(preg_split('/([.?!]\s*)/', $str, 0, PREG_SPLIT_DELIM_CAPTURE) as $token){
        if(!preg_match('/([.?!]\s*)/', $token, $m)) $token[0] = strtoupper($token[0]);
        $tokens[] = $token;
    }
    return implode($tokens);
}

// apply capitalization rules to individual words
function tidy_words($str){
    $tokens = array();
    foreach(preg_split('/([^\w-])/', $str, 0, PREG_SPLIT_DELIM_CAPTURE) as $token){
        switch(true){
            // tokens you want to uppercase go here
            case preg_match('/^(uk|kw)$/i', $token, $m): $tokens[] = strtoupper($m[0]); break;
            // tokens you want to lowercase go here
            case preg_match('/^(rpm|fl|oz)$/i', $token, $m): $tokens[] = strtolower($m[0]); break;
            // tokens you want to capitalize first letter go here
            case preg_match('/^(maxi-sense|side-by-side|d-radius)$/i', $token, $m): $tokens[] = ucfirst($m[0]); break;
            default: $tokens[] = $token;
        }
    }
    return implode($tokens);
}

function tidy($str){
    return tidy_sentences(tidy_words($str));
}

echo tidy('foo bar rpm maxi-sense uk Fl OZ baz! pull out');
// => Foo bar rpm Maxi-sense UK fl oz baz! Pull out

谢谢pguardiario,你是对的。我确实需要提高我的正则表达式能力。感谢你花时间研究这个问题并提供帮助。 - Adam Stacey

1

我认为最好的方法不一定是使用纯正则表达式。正则表达式的作用是用来匹配遵循特定模式的字符串。而你在这里的用例似乎并不是那么具体,所以我认为现在是时候探索另一种方法了。

我不确定你要清理的字符串有多复杂,或者通常包含什么内容(也许通常少于100个单词,并涉及某些特定主题,因此常见词汇很少)。然而,我认为更灵活(并且可能更容易)的解决方案将涉及一个更简单的正则表达式(或一组正则表达式),以识别您字符串中的标记。一旦您已经确定了特定的标记,您可以采取非常具体的行动,并基于标识标记对您的字符串执行更高级的算法。

我相信hakre的StringCleaner类是正确的路径,其思想是将不同类型的字符串抽象出来,使其远离核心逻辑,以帮助清理代码并使其更易于管理和灵活。

我知道这很泛泛而谈,但你要写的库的大小会非常快地膨胀 - 因为它涉及(基本上)自然语言处理,这是一种人工智能形式。


谢谢Jim,你说得对。仅使用正则表达式可能不是正确的方法。 - Adam Stacey

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