如何在PHP中解析以空格分隔的字符串?

时间:2011-06-25 23:34:27

标签: php parsing

我正在构建的PHP应用程序的一部分解析即将到来的工作和实习的RSS提要。每个Feed条目的<description>是一系列包含四个标准信息的标签或标签:

  1. 实习或工作
  2. 全职或兼职
  3. 类型(4种类型之一:本地政府,人力资源,非营利组织,其他)
  4. 组织名称
  5. 但是,所有内容都以空格分隔,将每个条目变成这样的混乱:

    • 实习全职本地Gov NASA
    • 工作兼职HR Deloitte
    • 工作全职非盈利联合之路

    我正在尝试解析每一行并使用字符串的各个部分作为变量。这个列表以任何标准方式分隔,我可以轻松地使用list($job, $time, $type, $name) = explode(",", $description)之类的东西来解析字符串并单独使用这些部分。

    但是,我不能用这些数据做到这一点。如果我使用explode(" "),我将获得许多无用的变量(例如“完整”,“时间”,“本地”,“政府”)。

    虽然列表没有分隔,但前三条信息是标准的,只能是2-4种不同的选项之一,实质上是创建一个允许条款的字典(除了最后一条 - 组织的名称 - 这是可变的)。因为这似乎我应该能够解析这些字符串,但我想不出最好/最干净/最快的方法。

    preg_replace似乎需要大量凌乱的正则表达式;一系列if / then语句(如果字符串包含“Local Gov”将$type设置为“Local Gov”)似乎很乏味,只会捕获前三个变量。

    那么,对于允许字符串的部分字典,解析非分隔字符串的最有效方法是什么?

    更新:我无法控制传入Feed数据的结构。如果我可以完全划定这一点,但遗憾的是不可能......

    更新2:为了澄清,前三个选项如下:

    1. 实习|工作
    2. 全职时间|兼职
    3. 本地政府|人力资源|非营利组织|其他
    4. 那是我正在谈论的伪词典。我需要以某种方式将这些字符串从主字符串中删除,并使用剩余的字符串作为组织名称。

6 个答案:

答案 0 :(得分:2)

这只是让你的手弄脏的问题:

$input = 'Internship Full time Local Gov NASA';

// Preconfigure known data here; these will end up
// in the output array with the keys defined here
$known_data = array(
    'job'  => array('Internship', 'Job'),
    'time' => array('Full time', 'Part time'),
    // add more known strings here
);

$parsed = array();
foreach($known_data as $key => $options) {
    foreach($options as $option) {
        if(substr($input, 0, strlen($option)) == $option) {
            // Skip recognized token and next space
            $input = substr($input, strlen($option) + 1);
            $parsed[$key] = $option;
            break;
        }
    }
}

// Drop all remaining tokens into $parsed with numeric
// keys; you could do something else with them if desired
$parsed += explode(' ', $input);

<强> See it in action

答案 1 :(得分:1)

<?php

$a = array (
'Internship Full time Local Gov NASA',
'Job Part time HR Deloitte',
'Job Full time Non-profit United Way',
);


foreach ($a as $s)
{
    if (preg_match ('/(Internship|Job)\s+(Part time|Full time)\s+(Local Gov|HR|Non-profit|Other)\s+(.*)/', $s, $match))
    {
        array_shift ($match);
        list($job, $time, $type, $name) =  $match;

        echo "$job, $time, $type, $name\n";
    }

}

答案 2 :(得分:1)

显然,最好的做法是更改RSS提要以使用不同的分隔符,或者(甚至更好)将这四个项目放入单独的标签/元素/属性/等等。

但假设这是不可能的:鉴于您所描述的内容,我将专注于使代码清晰,以牺牲性能和紧凑性为代价来阅读和维护(和修改)。代码将会更大,如果从4个字段到40个字段,它将无法很好地扩展,但如果您确信事情不会发生太大变化,那么您和任何必须接管维护代码的人都将是快乐。 (包括解释空间分隔问题的评论,以便人们理解你为什么这样做。)

所以,重新考虑这个问题。而不是一次解析所有字符串,找出如何只关闭第一个项目。 (我会在正则表达式中使用preg_match()^匹配每个可能性,以指示匹配必须出现在字符串的开头。如果正则表达式真的很长,因为字典很大但是没有特别的字符要担心,考虑将字典存储为数组并使用implode()创建由|分隔的字符串以用作正则表达式。)

对前三个元素执行三次(可能每次都从字符串中删除它),然后第四个元素是最后一个元素。

也许将每个元素检索例程放入自己的函数中,该函数调用后传函数来传递字典。然后,后续函数可以执行implode()并从字符串中拉出子字符串。

无论如何都是这样的。它不会是紧凑的代码,但有人阅读它将能够分辨出正在发生的事情并且正则表达式不会太疯狂。

答案 3 :(得分:0)

尝试以'\ n'分隔的爆炸然后在foreach中你可以杀死关键词,并且可能必须再次根据''爆炸。

答案 4 :(得分:0)

function startsWith($key, $data) {
   // get the length of the key we are looking for
   $len = strlen($key);
   // Check if the key matches the initial portion of the string
   if ($key === substr($data, 0, $len)) {
      // if yes return the remainder of the string
      return substr($data, $len);
   } else {
      // return false
      return false;
   }
}

这将允许您检查字符串是否以该字符串开头并相应地处理

答案 5 :(得分:0)

如果上面的字典完整,你可以取出非功能性的单词。

$input = str_replace(array('time', 'Gov'), '', $input);

现在你可以操作有意义的单个单词。