Regex для извлечения прогноза погоды и добавления в массив - PullRequest
1 голос
/ 21 февраля 2012

Я купил RegexBuddy, попробовал, и если я не сопоставляю что-то статичное и простое - я просто не могу получить регулярное выражение !

То, что я пытаюсь сделать, это из следующей строки текста; Я хотел бы извлечь информацию о приливе в ассоциативный массив.

High Tide: 2.0m on Mon at 08.54pm and 2.4m on Tue at 09.18am

И получим следующий массив:

[0] =
  'Day' => 'Mon',
  'Time' => '8.54pm',
  'Height' => '2.0m',
  'Tide' => 'High'

[1] =
  'Day' => 'Tue',
  'Time' => '09.18am',
  'Height' => '2.4m',
  'Tide' => 'High'

Концепция, с которой я больше всего борюсь, заключается в том, что есть несколько совпадений, которые я хочу извлечь (например, 2,0 м и 2,4 м). Мне удалось соответствовать на 2,0 м и 2,4 м, но как мне определить, какой из них какой? (Первый прилив против второго прилива).

Есть подсказки?

Ответы [ 4 ]

2 голосов
/ 21 февраля 2012
$string = "High Tide: 2.0m on Mon at 08.54pm and 2.4m on Tue at 09.18am";

preg_match_all("~((High|Low) Tide:)? (\d.\dm) on (\w{3}) at (.{7})~", $string, $matches, PREG_SET_ORDER);

var_dump($matches);

выходы

array
  0 => 
    array
      0 => string 'High Tide: 2.0m on Mon at 08.54pm' (length=33)
      1 => string 'High Tide:' (length=10)
      2 => string 'High' (length=4)
      3 => string '2.0m' (length=4)
      4 => string 'Mon' (length=3)
      5 => string '08.54pm' (length=7)
  1 => 
    array
      0 => string ' 2.4m on Tue at 09.18am' (length=23)
      1 => string '' (length=0)
      2 => string '' (length=0)
      3 => string '2.4m' (length=4)
      4 => string 'Tue' (length=3)
      5 => string '09.18am' (length=7)

Возможно, я неправильно понял, что такое отлив, поэтому вот код без прилива

$string = "High Tide: 2.0m on Mon at 08.54pm and 2.4m on Tue at 09.18am";

preg_match_all("~(\d.\dm) on (\w{3}) at (.{7})~", $string, $matches, PREG_SET_ORDER);

var_dump($matches);

выходы:

array
  0 => 
    array
      0 => string '2.0m on Mon at 08.54pm' (length=22)
      1 => string '2.0m' (length=4)
      2 => string 'Mon' (length=3)
      3 => string '08.54pm' (length=7)
  1 => 
    array
      0 => string '2.4m on Tue at 09.18am' (length=22)
      1 => string '2.4m' (length=4)
      2 => string 'Tue' (length=3)
      3 => string '09.18am' (length=7)
1 голос
/ 21 февраля 2012

Вы можете использовать именованные группы захвата , чтобы получить ассоциативный массив с результатом, и шаблон для сопоставления со строкой довольно прост.

/(?P<tide>high|low)\s+tide:\s+(?P<height1>\d+\.\d+m)\s+on\s+(?P<day1>[a-z]+)\s+at\s+(?P<time1>\d+\.\d+[ap]m)\s+and\s+(?P<height2>\d+\.\d+m)\s+on\s+(?P<day2>[a-z]+)\s+at\s+(?P<time2>\d+\.\d+[ap]m)/i

Пример сценария:

$string = "High Tide: 2.0m on Mon at 08.54pm and 2.4m on Tue at 09.18am";

// named groups will also assign matches associative to the matches array, e.g. (?P<tide>high|low) will set $matches["tide"] to 'low' or 'high'
preg_match(
        '/
            (?P<tide>high|low)                      # match and capture string "high" or "low"
            \s+tide:\s+                             # match string "tide" surrounded with one or more spaces on each side
            (?P<height1>\d+\.\d+m)                  # match and capture one or more digits followed by a dot and one or more digits followed by an m
            \s+on\s+                                # match string "on" surrounded with one or more spaces on each side
            (?P<day1>[a-z]+)                        # match one or more letters
            \s+at\s+                                # match string "at" surrounded with one or more spaces on each side
            (?P<time1>\d+\.\d+[ap]m)                # match and capture one or more digits followed by a dot and one or more digits followed by an a or p, and string "m", so am or pm
            \s+and\s+                               # match string "and" surrounded with one or more spaces on each side
            (?P<height2>\d+\.\d+m)                  # match and capture one or more digits followed by a dot and one or more digits followed by an m
            \s+on\s+                                # match string "on" surrounded with one or more spaces on each side
            (?P<day2>[a-z]+)                        # match one or more letters
            \s+at\s+                                # match string "at" surrounded with one or more spaces on each side
            (?P<time2>\d+\.\d+[ap]m)                # match and capture one or more digits followed by a dot and one or more digits followed by an a or p, and string "m", so am or pm
        /ix', $string, $matches);

print_r($matches);

это напечатает

Array
(
    [0] => High Tide: 2.0m on Mon at 08.54pm and 2.4m on Tue at 09.18am
    [tide] => High
    [1] => High
    [height1] => 2.0m
    [2] => 2.0m
    [day1] => Mon
    [3] => Mon
    [time1] => 08.54pm
    [4] => 08.54pm
    [height2] => 2.4m
    [5] => 2.4m
    [day2] => Tue
    [6] => Tue
    [time2] => 09.18am
    [7] => 09.18am
)
1 голос
/ 21 февраля 2012

вы можете использовать именованные группы , а затем ссылаться на то, что вы захватили по имени: (?P<name>exp) => $yourVarName['name']

(не проверено, но это было бы идеей)

/^[^\d]+(?P<heightOne>[\d\.]+?m)\son\s(?P<dayOne>\w+?)\sat\s(?P<timeOne>.*?(am|pm))\sand\s(?P<heightTwo>[\d\.]+?m)\son\s(?P<dayTwo>\w+?)\sat\s(?P<timeTwo>.*?(am|pm))$/
1 голос
/ 21 февраля 2012

Если слово and всегда разделяет два прилива, вы можете разбить строку на две части и обработать каждую половину отдельно.Например:

$str = "High Tide: 2.0m on Mon at 08.54pm and 2.4m on Tue at 09.18am";
$data = explode(" and ", $str);

$result = array();
foreach($data as $tide)
{
    $result[] = parseWithRegex($tide);
}
...