【问题标题】:explode string on multiple words在多个单词上爆炸字符串
【发布时间】:2016-02-23 05:25:34
【问题描述】:

有这样一个字符串:

$string = 'connector:rtp-monthly direction:outbound message:error writing data: xxxx yyyy zzzz date:2015-11-02 10:20:30';

此字符串来自用户输入。所以它永远不会有相同的顺序。这是一个输入字段,我需要对其进行拆分以构建数据库查询。

现在我想根据 array() 中给出的单词拆分字符串,这就像一个包含我需要在字符串中找到的单词的映射器。看起来像这样:

$mapper = array(
    'connector' => array('type' => 'string'),
    'direction' => array('type' => 'string'),
    'message' => array('type' => 'string'),
    'date' => array('type' => 'date'),
);

只有$mapper 的键是相关的。我尝试过使用 foreach 并像这样爆炸:

 $parts = explode(':', $string);

但问题是:字符串中的某处可能有冒号,所以我不需要在那里爆炸。如果在映射器键之后紧跟一个冒号,我只需要爆炸。在这种情况下,映射器键是:

connector    // in this case split if "connector:" is found
direction    // untill "direction:" is found
message      // untill "message:" is found
date         // untill "date:" is found

但请记住,用户输入可以变化。所以字符串总是会改变字符串的顺序,mapper array() 永远不会是相同的顺序。所以我不确定爆炸是否是正确的方法,或者我是否应该使用正则表达式。如果是的话怎么做。

所需的结果应该是一个如下所示的数组:

$desired_result = array(
    'connector' => 'rtp-monthly',
    'direction' => 'outbound',
    'message' => 'error writing data: xxxx yyyy zzzz',
    'date' => '2015-11-02 10:20:30',
);

非常感谢您的帮助。

【问题讨论】:

  • 按空格分割,之后按:
  • 它可以用一个正则表达式来完成,你有没有机会将该字符串更改为更容易解析的格式(例如 json 等)?
  • $result = array_column(array_map(function($v){return explode(":", $v);}, explode(" ", $string)), 1, 0);
  • /([^:\s]+):(\S+)/ 两个捕获组,一个在冒号之前,一个在冒号之后。另外使用preg_match_all()writingdata 可以忽略吗?
  • 意味着您无法控制格式......这太糟糕了,考虑到以下所有答案都涉及更多工作:D

标签: php arrays regex explode


【解决方案1】:

PHP中使用preg_split()通过多个分隔符来explode()

这里只是一个简短的说明。要在 PHP 中使用多个分隔符来爆炸()字符串,您必须使用正则表达式。使用竖线字符分隔分隔符。

$string = 'connector:rtp-monthly direction:outbound message:error writing data: xxxx yyyy zzzz date:2015-11-02 10:20:30';
$chunks = preg_split('/(connector|direction|message)/',$string,-1, PREG_SPLIT_NO_EMPTY);

// Print_r to check response output.
echo '<pre>';
print_r($chunks);
echo '</pre>';

PREG_SPLIT_NO_EMPTY – 只返回非空件。

【讨论】:

    【解决方案2】:

    其中比较棘手的部分是匹配原始字符串。您可以在lookahead positive assertions 的帮助下使用正则表达式来完成:

    $pattern = "/(connector|direction|message|date):(.+?)(?= connector:| direction:| message:| date:|$)/";
    $subject = 'connector:rtp-monthly direction:outbound message:error writing data: xxxx yyyy zzzz date:2015-11-02 10:20:30';
    
    preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER );
    
    $returnArray = array();
    foreach($matches as $item)
    {
        $returnArray[$item[1]] = $item[2];
    }
    

    在这个正则表达式 /(connector|direction|message|date):(.+?)(?= connector:| direction:| message:| date:|$)/ 中,您正在匹配:

    • (connector|direction|message|date) - 找到一个关键字并捕获它;
    • : - 后跟一个冒号;
    • (.+?) - 后跟任意字符多次非贪婪,并捕获它;
    • (?= connector:| direction:| message:| date:|$) - 直到下一个关键字或字符串结尾,使用非捕获前瞻肯定断言。

    结果是:

    Array
    (
        [connector] => rtp-monthly
        [direction] => outbound
        [message] => error writing data: xxxx yyyy zzzz
        [date] => 2015-11-02 10:20:30
    )
    

    我没有使用映射器数组只是为了使示例清晰,但您可以使用implode 将关键字放在一起。

    【讨论】:

    • 如何在$pattern 中插入$mapper = array() 的密钥?
    • 我不清楚这个 $mapper 数组的目的是什么。如果您可以编辑您的问题并澄清预期的行为,这将有所帮助。此外,您更新的字符串会破坏此正则表达式,因为您也使用分隔符(冒号)作为数据的一部分(时间部分)。如果可能,我强烈建议您将输入格式更改为 JSON 之类的格式。
    • 问题已更新,现在更有意义了。我知道,分隔符,这是我的问题的一部分。这就是为什么我想在分隔符前面使用那些“映射词”。或者分隔符与那些映射词的组合......
    • 我已经编辑了我的答案,我认为它达到了你现在所需要的。
    【解决方案3】:

    您可以使用正则表达式和explode() 的组合。考虑以下代码:

    $str = "connector:rtp-monthly direction:outbound message:error writing data date:2015-11-02";
    $regex = "/([^:\s]+):(\S+)/i";
    // first group: match any character except ':' and whitespaces
    // delimiter: ':'
    // second group: match any character which is not a whitespace
    // will not match writing and data
    preg_match_all($regex, $str, $matches);
    $mapper = array();
    foreach ($matches[0] as $match) {
        list($key, $value) = explode(':', $match);
        $mapper[$key][] = $value;
    }
    

    此外,您可能首先要考虑一种更好的方式来存储字符串(JSON?XML?)。

    【讨论】:

      【解决方案4】:

      给你。正则表达式用于“捕捉”键(任何字符序列,不包括空格和“:”)。从那里开始,我使用“explode”来“递归”拆分字符串。经过测试的广告效果很好

      $string = 'connector:rtp-monthly direction:outbound message:error writing data date:2015-11-02';
      
      $element = "(.*?):";
      preg_match_all( "/([^\s:]*?):/", $string, $matches);
      $result = array();
      $keys = array();
      $values = array();
      $counter = 0;
      foreach( $matches[0] as $id => $match ) {
          $exploded = explode( $matches[ 0 ][ $id ], $string );
          $keys[ $counter ] = $matches[ 1 ][ $id ];
          if( $counter > 0 ) {
              $values[ $counter - 1 ] = $exploded[ 0 ];
          }
          $string = $exploded[ 1 ];
          $counter++;
      }
      $values[] = $string;
      $result = array();
      foreach( $keys as $id => $key ) {
          $result[ $key ] = $values[ $id ];
      }
      print_r( $result );
      

      【讨论】:

      • 谢谢!请查看有问题的更新字符串:$string = 'connector:rtp-monthly direction:outbound message:error writing data: xxxx date:2015-11-02 10:20:30'; 我认为我真的需要拆分给定的mapper array()
      【解决方案5】:

      我们的目标是创建一个数组,其中包含我们将从字符串中提取的两个数组的值。有两个数组是必要的,因为我们希望考虑两个字符串分隔符。 试试这个:

      $parts = array();
      $large_parts = explode(" ", $string);
      
      for($i=0; $i<count($large_parts); $i++){
          $small_parts = explode(":", $large_parts[$i]);
          $parts[$small_parts[0]] = $small_parts[1];
      }
      

      $parts 现在应该包含所需的数组

      希望你能解决问题。

      【讨论】:

      • 虽然这段代码 sn-p 可以解决问题,但代码外的including an explanation 确实有助于提高帖子的质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性的 cmets 挤满你的代码,这会降低代码和解释的可读性!
      • @TroubleZero 感谢您的回答。这不会真正帮助我。考虑我可以得到一个包含日期值的字符串,例如date:2015-11-02 08:10:15,所以我真的需要并且想要拆分解释的映射数组键...
      • 对于日期部分,您可以先将“:”替换为“-”或“/”以避免格式混淆。
      猜你喜欢
      • 2011-09-04
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多