【问题标题】:Unset array if preg_match does not match pattern?如果 preg_match 与模式不匹配,则取消设置数组?
【发布时间】:2015-05-18 23:24:48
【问题描述】:

我有一个如下所示的多维数组:

Array
(
    [0] => Array
        (
            [0] => Title 1
            [1] => Some text ... US5801351017 ...
        )

    [1] => Array
        (
            [0] => Title 2
            [1] => Some text ... US0378331005 ...
        )

    [2] => Array
        (
            [0] => Title 3
            [1] => Some text ... //Note here that it does not contain an ISIN Code
        )
...

我正在尝试过滤掉与我的正则表达式匹配且包含 ISIN 代码的数组。上面的数组是由以下代码生成的:

$title = $html->find("h3.r a");
$titlearray = array_map(function($value){
    return trim($value->plaintext);
}, $title);

$description = $html->find("span.st");
$descriptionarray = array_map(function($value){
    $string = strip_tags($value);
    return $string;
}, $description);

$result1 = array();
foreach($titlearray as $key => $value) {
    $tmp = array($value);
    if (isset($descriptionarray[$key])) {
        $tmp[] = $descriptionarray[$key];
    }
    $result1[] = $tmp;
}

print_r($result1);

我编写了一些代码,它们非常接近但并不真正unset 不包含 ISIN 代码的数组。我的代码是这样的:

$title = $html->find("h3.r a");
$titlearray = array_map(function($value){
    return trim($value->plaintext);
}, $title);

$description = $html->find("span.st");
$descriptionarray = array_map(function($value){
    $match = array();
    $string = strip_tags($value);
    $pattern = "/[BE|BM|FR|BG|VE|DK|HR|DE|JP|HU|HK|JO|US|BR|XS|FI|GR|IS|RU|LB|"
            . "PT|NO|TW|UA|TR|LK|LV|LU|TH|NL|PK|PH|RO|EG|PL|AA|CH|CN|CL|EE|CA|"
            . "IR|IT|ZA|CZ|CY|AR|AU|AT|IN|CS|CR|IE|ID|ES|PE|TN|PA|SG|IL|US|MX|"
            . "SK|KRSI|KW|MY|MO|SE|GB|GG|KY|JE|VG|NG|SA|MU]{2}[A-Z0-9]{10}/";
    preg_match($pattern, $string, $match);
    return $match;
}, $description);

$merged = array();
$i=0;
foreach($descriptionarray as $value){
  $merged[$i] = $value;
  $merged[$i][] = $titlearray[$i];
  $i++;
}

print_r($merged);

这给了我这些数组:

Array
(
    [0] => Array
        (
            [0] => US5801351017
            [1] => Title 1
        )

    [1] => Array
        (
            [0] => US0378331005
            [1] => Title 2
        )

    [2] => Array
        (
            [0] => Title 3
        )
...

我怎样才能摆脱与我的正则表达式不匹配的数组?我正在寻找的是这个输出:

Array
(
    [0] => Array
        (
            [0] => Title 1
            [1] => US5801351017
        )

    [1] => Array
        (
            [0] => Title 2
            [1] => US0378331005
        )
...

编辑

@CasimiretHippolyte

根据他的回答,我现在有这个代码:

$titles = $html->find("h3.r a");

$descriptions = $html->find("span.st");

$ISIN_PATTERN = "/[BE|BM|FR|BG|VE|DK|HR|DE|JP|HU|HK|JO|US|BR|XS|FI|GR|IS|RU|LB|"
            . "PT|NO|TW|UA|TR|LK|LV|LU|TH|NL|PK|PH|RO|EG|PL|AA|CH|CN|CL|EE|CA|"
            . "IR|IT|ZA|CZ|CY|AR|AU|AT|IN|CS|CR|IE|ID|ES|PE|TN|PA|SG|IL|US|MX|"
            . "SK|KRSI|KW|MY|MO|SE|GB|GG|KY|JE|VG|NG|SA|MU]{2}[A-Z0-9]{10}/";

$results = [];

foreach ($descriptions as $k => $v) {
    if (preg_match($ISIN_PATTERN, strip_tags($v), $m)) {
        $results[] = ['Title' => trim($titles[$k]->plaintext), 'ISIN' => $m[1]];
    }
}

print_r($results);

这会缩小我的数组范围,仅选择与正则表达式匹配的元素,但不会在 'ISIN' => $m[1] 下显示匹配项。它输出这个:

Array
(
    [0] => Array
        (
            [Title] => Title 1
            [ISIN] => 
        )

    [1] => Array
        (
            [Title] => Title 2
            [ISIN] => 
        )
...

进一步编辑

这段代码解决了这个问题:

$titles = $html->find("h3.r a");

$descriptions = $html->find("span.st");

$ISIN_PATTERN = "/[BE|BM|FR|BG|VE|DK|HR|DE|JP|HU|HK|JO|US|BR|XS|FI|GR|IS|RU|LB|"
            . "PT|NO|TW|UA|TR|LK|LV|LU|TH|NL|PK|PH|RO|EG|PL|AA|CH|CN|CL|EE|CA|"
            . "IR|IT|ZA|CZ|CY|AR|AU|AT|IN|CS|CR|IE|ID|ES|PE|TN|PA|SG|IL|US|MX|"
            . "SK|KRSI|KW|MY|MO|SE|GB|GG|KY|JE|VG|NG|SA|MU]{2}[A-Z0-9]{10}/";

$results1 = [];

foreach ($descriptions as $k => $v) {
    if (preg_match($ISIN_PATTERN, strip_tags($v), $m)) {
        $results1[] = ['Title' => trim($titles[$k]->plaintext), 'ISIN' => $m[1]];
    }
}

$titlesarray = array_column($results1, 'Title');

$results2 = array_map(function($value){
    $match = array();
    $string = strip_tags($value);
    $pattern = "/[BE|BM|FR|BG|VE|DK|HR|DE|JP|HU|HK|JO|US|BR|XS|FI|GR|IS|RU|LB|"
            . "PT|NO|TW|UA|TR|LK|LV|LU|TH|NL|PK|PH|RO|EG|PL|AA|CH|CN|CL|EE|CA|"
            . "IR|IT|ZA|CZ|CY|AR|AU|AT|IN|CS|CR|IE|ID|ES|PE|TN|PA|SG|IL|US|MX|"
            . "SK|KRSI|KW|MY|MO|SE|GB|GG|KY|JE|VG|NG|SA|MU]{2}[A-Z0-9]{10}/";
    preg_match($pattern, $string, $match);
    return $match;
}, $descriptions);

$descriptionarray = array_column($results2, 0);

$result3 = array();
foreach($titlesarray as $key => $value) {
    $tmp = array($value);
    if (isset($descriptionarray[$key])) {
        $tmp[] = $descriptionarray[$key];
    }
    $result3[] = $tmp;
}

print_r($result3);

因为我需要一个快速的解决方案,所以我非常快速地拼凑了一些东西。这是非常低效的,因为我使用了一个额外的arrar_map(),将数组简化为一个简单数组,然后将它们重新组合在一起。除此之外,我重复我的正则表达式。


最后编辑

@CasimiretHippolyte 的答案是最有效的解决方案,它给出了将他的模式与$m[1] 或我的模式与$m[0] 一起使用的答案。

【问题讨论】:

  • 我可以在我的正则表达式中使用array_filter() 吗? @rjdown
  • 你可以在回调函数中使用任何你喜欢的东西,就像你使用array_map一样。您只需要在最后返回 true 或 false,这将决定是否保留元素。
  • 使用简单的foreach 来构建您的数组,而不是array_map
  • @CasimiretHippolyte 为什么?
  • @hek2mgl:因为使用 foreach 可以在同一个循环中提取(和过滤)标题和 ISIN,而不是使用多个隐藏循环(array_map + array_map + array_filter)。

标签: php arrays regex foreach


【解决方案1】:

您可以使用简单的 foreach 以其他方式设计您的代码,并仅在找到 ISIN 代码时逐个构建结果项:

$titles = $html->find("h3.r a");
$descriptions = $html->find("span.st");

define ('ISIN_PATTERN', '~
 \b  # there is probably a word boundary at the begin of the ISIN code
 (?=([A-Z]{2}[A-Z0-9]{10})\b) # check the format before testing the whole alternation
                              # at the same time, the ISIN is captured in group 1
 (?: # so, this alternation is only here to make the pattern fail or succeed
     C[AHLNRSYZ]|I[DELNRST]|P[AEHKLT]|S[AEIGK]|A[ARTU]|B[EGMR]|L[BKUV]|M[OUXY]|T[HNRW]
     |E[EGS]|G[BGR]|H[KRU]|J[EOP]|K[RWY]|N[GLO]|D[EK]|F[IR]|R[OU]|U[AS]|V[EG]|XS|ZA
 )~x');

$results = [];

foreach ($descriptions as $k => $v) {
    if (preg_match(ISIN_PATTERN, strip_tags($v), $m))
        $results[] = [ 'ISIN' => $m[1], 'Title' => trim($titles[$k]->plaintext) ]; 
}

print_r($results);

注意:此代码未经测试,可能需要改进。几个想法:

  • 停止使用 simplehtml 并使用 DOMDocument 和 DOMXPath
  • 手动模式的设计假设所有国家都是等概率的。如果不是这样,请重写它以优先检查最新的国家/地区

【讨论】:

  • 非常感谢您的帮助。您的代码简化了我的数组,但将“ISIN”留空。看看我的编辑。为什么 ? @CasimiretHippolyte
  • @AvaBarbilla:您使用的模式是错误的,[BE|BM|FR] 不是您的意思,因为字符类中的| 是文字字符,不再是逻辑或 (写[BEFMR|])也是一样的。在我的模式中,ISIN 代码被捕获在第 1 组中,这就是我稍后使用$m[1] 的原因。如果您决定使用没有捕获组的其他模式,请使用$m[0](代表整个匹配)。
  • 非常感谢@CasimiretHippolyte。它适用于两种模式,将 $m[1] 与您的模式一起使用,或者将 $m[0] 与我的模式一起使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-15
  • 2018-05-16
  • 2016-08-01
  • 1970-01-01
  • 2021-04-29
  • 2022-01-09
  • 1970-01-01
相关资源
最近更新 更多