PHP正则表达式:在另一个表达式中多次匹配整个表达式

时间:2018-06-26 08:19:29

标签: php regex

摘要

要匹配的示例字符串:

  

Test1 Test2 Test3 之后

之前

需要正则表达式:

  

(表达式)之后

之前

详细说明

我在使用PHP的正则表达式时遇到问题,即使经过广泛的搜索和无数次尝试,我仍然无法正确处理它,这确实令人发指。

这是我要分析的字符串:

  

“位置”:[{“ id”:1204,“名称”:“房间1”},{“ id”:1205,“名称”:“房间   2“},{” id“:1206,” name“:”房间3“},{” id“:1207,” name“:”房间   4“},{” id“:1208,” name“:”房间5“},{” id“:1209,” name“:”房间   6“},{” id“:1210,” name“:” 7号房间“},{” id“:1211,” name“:” 1号房间“}]

格式化以提高可读性

"places":[
  {
    "id":1204,
    "name":"Room 1"
  },
  {
    "id":1205,
    "name":"Room 2"
  },
  {
    "id":1206,
    "name":"Room 3"
  },
  {
    "id":1207,
    "name":"Room 4"
  },
  {
    "id":1208,
    "name":"Room 5"
  },
  {
    "id":1209,
    "name":"Room 6"
  },
  {
    "id":1210,
    "name":"Room 7"
  },
  {
    "id":1211,
    "name":"Room 1"
  }
]

使用 preg_match_all 时的结果应为以下数组:

Array
(
  [0] => Array
  (
    [0] => {"id":1204,"name":"Room 1"}
    [1] => {"id":1205,"name":"Room 2"}
    [2] => {"id":1206,"name":"Room 3"}
    [3] => {"id":1207,"name":"Room 4"}
    [4] => {"id":1208,"name":"Room 5"}
    [5] => {"id":1209,"name":"Room 6"}
    [6] => {"id":1210,"name":"Room 7"}
    [7] => {"id":1211,"name":"Room 1"}
  )
  [1] => Array
  (
    [0] => 1204
    [1] => 1205
    [2] => 1206
    [3] => 1207
    [4] => 1208
    [5] => 1209
    [6] => 1210
    [7] => 1211
  )
  [2] => Array
  (
    [0] => Room 1
    [1] => Room 2
    [2] => Room 3
    [3] => Room 4
    [4] => Room 5
    [5] => Room 6
    [6] => Room 7
    [7] => Room 1
   )
)

现在我像这样连续两次使用 preg_match_all

preg_match_all('/\"places\"\:\[(.*)\]/', $places_string, $raw_string_to_analyse);

现在我有中间部分:

  

{“ id”:1204,“ name”:“房间1”}},{“ id”:1205,“ name”:“房间   2“},{” id“:1206,” name“:”房间3“},{” id“:1207,” name“:”房间   4“},{” id“:1208,” name“:”房间5“},{” id“:1209,” name“:”房间   6“},{” id“:1210,” name“:”房间7“},{” id“:1211,” name“:”房间1“}}

现在我正在像这样提取信息:

preg_match_all('/\{\"id\"\:([0-9]*),\"name\"\:\"(.*?)\"\}/', $places, $middle_part);

现在我有了所需的信息。

不幸的是,我无法将这两个表达式组合成一个这样的表达式:

  

[MATCH_BEFORE] [MATCH_IN_THE_MIDDLE] {视需要而定} [MATCH_AFTER]

所以我必须将第一个表达式中的(。 替换为 {\“ id \”:([0-9] ),\“名称\”:\“(。*?)\”},? (请注意末尾的可选逗号)

我无法找到一种方法将内部表达式括在方括号(或任何需要的内容)中,并使其匹配一定次数(*)。

我希望有人能够为我提供帮助,因为现在我很生气,因为我不知道该怎么做。

2 个答案:

答案 0 :(得分:1)

该字符串实际上是一个json字符串。话虽如此,您只需要对其解码并对结果进行一些数据提取即可:

$string = '{"places":[{"id":1204,"name":"Room 1"},{"id":1205,"name":"Room 2"},{"id":1206,"name":"Room 3"},{"id":1207,"name":"Room 4"},{"id":1208,"name":"Room 5"},{"id":1209,"name":"Room 6"},{"id":1210,"name":"Room 7"},{"id":1211,"name":"Room 1"}]}';

$data = json_decode($string, true);
$ids = array_column($data['places'], 'id');
$names = array_column($data['places'], 'name');

以后编辑

为达到相同的结果,但使用正则表达式,您可以使用的唯一正则表达式为/{"id":([0-9]+),"name":"([\w\s]+)"}/。匹配项将恰好是您在问题中期望的匹配项:

preg_match_all('/{"id":([0-9]+),"name":"([\w\s]+)"}/', $string, $matches);

echo '<pre>';
var_dump($matches);
echo '</pre>';

结果将是:

array(3) {
  [0]=>
  array(8) {
    [0]=>
    string(27) "{"id":1204,"name":"Room 1"}"
    [1]=>
    string(27) "{"id":1205,"name":"Room 2"}"
    [2]=>
    string(27) "{"id":1206,"name":"Room 3"}"
    [3]=>
    string(27) "{"id":1207,"name":"Room 4"}"
    [4]=>
    string(27) "{"id":1208,"name":"Room 5"}"
    [5]=>
    string(27) "{"id":1209,"name":"Room 6"}"
    [6]=>
    string(27) "{"id":1210,"name":"Room 7"}"
    [7]=>
    string(27) "{"id":1211,"name":"Room 1"}"
  }
  [1]=>
  array(8) {
    [0]=>
    string(4) "1204"
    [1]=>
    string(4) "1205"
    [2]=>
    string(4) "1206"
    [3]=>
    string(4) "1207"
    [4]=>
    string(4) "1208"
    [5]=>
    string(4) "1209"
    [6]=>
    string(4) "1210"
    [7]=>
    string(4) "1211"
  }
  [2]=>
  array(8) {
    [0]=>
    string(6) "Room 1"
    [1]=>
    string(6) "Room 2"
    [2]=>
    string(6) "Room 3"
    [3]=>
    string(6) "Room 4"
    [4]=>
    string(6) "Room 5"
    [5]=>
    string(6) "Room 6"
    [6]=>
    string(6) "Room 7"
    [7]=>
    string(6) "Room 1"
  }
}

如果您有多个键,并且只需要匹配位置,则必须首先提取所有位置值,并对结果执行preg_match_all:

preg_match('/(?<=places"\:\[).*?(?=\])/', $string, $match);
preg_match_all('/{"id":([0-9]+),"name":"([\w\s]+)"}/', $match[0], $matches);

echo '<pre>';
var_dump($matches);
echo '</pre>';

答案 1 :(得分:0)

首先,让我明确宣布您不应尝试通过使用正则表达式解析其值来滥用有效的json字符串 ... unless you have a seriously compelling reason to do so.

Matei涉及json_decode()array_column()的解决方案正是我编写代码的方式,应该是你编写代码的方式,因为它是直接的并且采用最佳实践(假设json有效)。

对于不是 json的理论/未发布数据,但您希望执行全局重复匹配...是的,您可以利用以下技巧来执行单个聪明的regex函数调用: \G

一些文档可以帮助您了解如何继续匹配重复序列。 https://www.regular-expressions.info/continue.html

Pattern Demo(使用您的json数据)

代码:(Demo

$json = <<<JSON
{"places":[{"id":1204,"name":"Room 1"},{"id":1205,"name":"Room 2"},{"id":1206,"name":"Room 3"},{"id":1207,"name":"Room 4"},{"id":1208,"name":"Room 5"},{"id":1209,"name":"Room 6"},{"id":1210,"name":"Room 7"},{"id":1211,"name":"Room 1"}]}
JSON;

if (preg_match_all('~(?:\G,|\{"places":\[)\K\{"id":(\d+),"name":"([^"]+)"}~', $json, $matches)) {
    unset($matches[0]);  // throw away the fullstring matches subarray
    var_export($matches);
}

输出:

array (
  1 => 
  array (
    0 => '1204',
    1 => '1205',
    2 => '1206',
    3 => '1207',
    4 => '1208',
    5 => '1209',
    6 => '1210',
    7 => '1211',
  ),
  2 => 
  array (
    0 => 'Room 1',
    1 => 'Room 2',
    2 => 'Room 3',
    3 => 'Room 4',
    4 => 'Room 5',
    5 => 'Room 6',
    6 => 'Room 7',
    7 => 'Room 1',
  ),
)