【问题标题】:PHP extract values from a stringPHP从字符串中提取值
【发布时间】:2012-01-06 13:34:12
【问题描述】:

我正在用 PHP 处理记录,想知道是否有一种有效的方法来提取类型:以下每个记录中的值。流派:可以是字符串中的任何位置。

在下面的字符串中我需要抽出单词“alternative”(最后一个单词)

[media:keywords] => upc:00602527365589,Records,mercury,artist:Neon 
 Trees,Alternative,trees,neon,genre:alternative

在下面的字符串中我需要拉出“Latin / Pop,latino,Pop”

[media:keywords] => genre:Latin / Pop,latino,Pop,upc:00602527341217,artist:Luis 
 Fonsi,luis,universal,Fonsi,Latin

在下面的记录中我需要抽出“其他”

[media:keywords] => upc:793018101530,andy,razor,Other,tie,genre:other,artist:Andy 
McKee,McKee,&

在下面的记录中我需要拉出“rock,flotsam,jetsam”

[media:keywords] => and,upc:00602498572061,genre:rock,flotsam,jetsam,artist:Flotsam 
And Jetsam,rock,geffen

我在这上面扯了我的头发(反正还剩下什么)。

【问题讨论】:

  • 我不擅长使用正则表达式,但我做到了(genre:).*(?=.*\:) 是我能做的最大值。如果有人可以进化它..

标签: php regex substr


【解决方案1】:

使用下面的正则表达式加上preg_match()

~\bgenre:(.+?)(?=(,[^:,]+:|$))~

您想要的结果将在匹配数组的第一个元素中(参数 3)。

【讨论】:

  • 感谢博士。我对 300 条记录进行了测试...所有记录都完美匹配..现在我希望下一个 50k 可以做哈哈...真的再次感谢
【解决方案2】:

我将使用 strpos 来定义流派的开始位置。您唯一的问题是在哪里结束它,因为您没有分隔符。我应该使用已知的其他关键字,如“upc”、“artist”等来检查字符串是否需要在末尾被剪切。

【讨论】:

    【解决方案3】:

    您确实可以使用一点模式检测。您总是在寻找固定的genre:,后跟一个或多个单词或短语,它们本身都不能包含:

    所以这可能就足够了:

    preg_match('~\bgenre:(,?[^:,]+(?=,|$))+~', $media_keywords, $match);
    print $match[1];
    

    【讨论】:

    • 这个正则表达式不起作用。对于第一个示例,它匹配“alternative”,就像它应该匹配的那样,但对于其他示例,它分别匹配“,upc”、“,artist”和“,artist”。
    • 您的意思可能是~\bgenre:((,?[^:,]+)+)~,所以$match[1] 包含所有重复的流派。然而,即使这是不正确的,因为[^:,]+ 仍将匹配下一个“类别”。例如,“upc”或“艺术家”。
    • 不,它停在,Pop。但是额外的捕获组是不可避免的。
    • 您的新正则表达式 ~\bgenre:(,?[^:,]+(?=,|$))+~ 仍然匹配不正确。它匹配“alternative”、“,Pop”、“other”和“,jetsam”。
    【解决方案4】:
    $mystring = 'abc';
    $findme   = 'a';
    $pos = strpos($mystring, $findme);
    
    // Note our use of ===.  Simply == would not work as expected
    // because the position of 'a' was the 0th (first) character.
    if ($pos === false) {
        echo "The string '$findme' was not found in the string '$mystring'";
    } else {
        echo "The string '$findme' was found in the string '$mystring'";
        echo " and exists at position $pos";
    }
    

    来自strpos 的 PHP 文档

    所以你可以使用$findme = "alternative"

    【讨论】:

      【解决方案5】:

      解析此字符串的问题是您没有正常的分隔符和/或引号(即逗号分隔字段,但也可以包含在字段中 - 这与不带引号的 CSV 文件存在相同的问题) .

      如果性能对您来说并不重要,我建议以更防弹的方式对其进行解析,例如对什么是关键(如艺术家、流派、ups 等)做出一些假设并引入一些正常的分隔符,概念验证代码将是:(我留下了回声,所以你可以看到发生了什么)

      $string = "genre:Latin / Pop,latino,Pop,upc:00602527341217,artist:Luis Fonsi,luis,universal,Fonsi,Latin";
      //introduce a delimiter
      $delimiter = '|';
      $withDelimiter = preg_replace('/([a-z]+):/', $delimiter . '$0', $string);
      echo $withDelimiter . "\n";
      
      $fields = explode($delimiter, $withDelimiter);
      foreach ($fields as $field) {
          if (strlen($field)) {
              echo $field . "\n";
      
              list ($key, $valueWithPossiblyTrailingComma) = explode(':', $field);    
      
              if ($key === 'genre') {
                  $genre = rtrim($valueWithPossiblyTrailingComma, ',');
                  break;
              }
          }
      }
      echo $genre;
      

      你可以让它在几乎所有情况下都工作,它不仅可以让你找到任何关键流派 - 但它的性能会很低。

      我对你的字符串做了以下假设:

      • 它是由冒号分隔并用逗号连接的键 => 值对列表
      • 键可能只有 [a-z] 个字符

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-01
        • 1970-01-01
        相关资源
        最近更新 更多