Regex для анализа строки и захвата строки и числа, разделенных запятыми - PullRequest
0 голосов
/ 10 ноября 2018

Я пытаюсь проанализировать файл со строками, похожими на:

       John David James (DEM) .  .  .  .  .  .     7,808   10.51
       Marvin D. Scott (DEM)  .  .  .  .  .  .     6,548    9.55
       Maria "Mary" Williams (DEM)  .  .  .  .     4,551    8.58
       Dwayne R. Johnson.  .  .  .  .  .  .  .     4,322    8.22
       WRITE-IN.  .  .  .  .  .  .  .  .  .  .       188     .29

Мне нужно захватить имя и число в первом столбце . Конечный результат будет

John David James (DEM),7808
Marvin D. Scott (DEM),6548
Maria "Mary" Williams (DEM),4551
Dwayne R. Johnson,4322
WRITE-IN,188

Я пробовал

\s*\b(.*)\b(\s*\.\s*.*)(\d+,\d+|\d+)\b
\s*\b(.*)\b(\.|.\s)+\b(\d+,\d+|\d+)\b

Есть предложения?

Ответы [ 3 ]

0 голосов
/ 10 ноября 2018

Вы можете достичь этого с помощью НЕДОРОГОГО регулярного выражения.

Здесь, когда мы ловим имя, мы хотим «последовательность любого символа, за которой следует последовательность точек и пробелов». Итак, вот эквивалентное регулярное выражение: (.+)[. ]*.

Но двигатель установлен в жадный режим по умолчанию. Что случится? Первая часть (.+) не остановится на первой точке или первой найденной пробел. Зачем? Потому что можно выполнить все регулярные выражения до конца строки, и движок выберет этот путь, как в жадном режиме.

То же самое относится ко всему регулярному выражению, которое вы можете увидеть в рабочем коде ниже. Первая группа захвата будет захватывать за пределами поля имени.

Нам нужно сказать ему «съесть» менее подходящую часть.

<code><?php
$lines = '
       John David James (DEM) .  .  .  .  .  .     7,808   10.51
       Marvin D. Scott (DEM)  .  .  .  .  .  .     6,548    9.55
       Maria "Mary" Williams (DEM)  .  .  .  .     4,551    8.58
       Dwayne R. Johnson.  .  .  .  .  .  .  .     4,322    8.22
       WRITE-IN.  .  .  .  .  .  .  .  .  .  .       188     .29
';
$lines = explode("\n", $lines);

// Here, the U flag sets the ungreedy mode
$pattern = '/^\s*(\S.+\S)[. ]+([0-9]+)(?:,([0-9]+))?\s.*$/U';
echo "<pre>";
foreach ($lines  as $line) {
    // Here : - ${1} will capture the name,
    //        - ${2} the integer part of the number
    //        - ${3} the decimal part
    echo preg_replace($pattern, '${1},${2}${3}', $line) . "\n";
}
echo "
"; ?>

Результат:

John David James (DEM),7808
Marvin D. Scott (DEM),6548
Maria "Mary" Williams (DEM),4551
Dwayne R. Johnson,4322
WRITE-IN,188
0 голосов
/ 10 ноября 2018

Этот шаблон захватывает имя, находя последовательность точек после имени.
Затем захватывает число и запятую как число.

Затем я делаю цикл для создания нового массива и заменяю запятую ничем.

$str = '       John David James (DEM) .  .  .  .  .  .     7,808   10.51
       Marvin D. Scott (DEM)  .  .  .  .  .  .     6,548    9.55
       Maria "Mary" Williams (DEM)  .  .  .  .     4,551    8.58
       Dwayne R. Johnson.  .  .  .  .  .  .  .     4,322    8.22
       WRITE-IN.  .  .  .  .  .  .  .  .  .  .       188     .29';
preg_match_all("/\s*(.*?)\s*\.  \..*?([\d,]+)/", $str, $matches);

foreach($matches[1] as $key => $name){
    $new[] = $name . "," . str_replace(",", "", $matches[2][$key]);
}


var_dump($new);

Выход:

array(5) {
  [0]=>
  string(27) "John David James (DEM),7808"
  [1]=>
  string(26) "Marvin D. Scott (DEM),6548"
  [2]=>
  string(32) "Maria "Mary" Williams (DEM),4551"
  [3]=>
  string(22) "Dwayne R. Johnson,4322"
  [4]=>
  string(12) "WRITE-IN,188"
}

https://3v4l.org/SdqoZ

0 голосов
/ 10 ноября 2018

Если данные выровнены по столбцам (все столбцы имеют фиксированную ширину), используйте строковые функции, такие как substr:

<?php
$lines = '
       John David James (DEM) .  .  .  .  .  .     7,808   10.51
       Marvin D. Scott (DEM)  .  .  .  .  .  .     6,548    9.55
       Maria "Mary" Williams (DEM)  .  .  .  .     4,551    8.58
       Dwayne R. Johnson.  .  .  .  .  .  .  .     4,322    8.22
       WRITE-IN.  .  .  .  .  .  .  .  .  .  .       188     .29
';

foreach(preg_split('/(\\r|\\n)+/', $lines) as $line) {
    if ($line === '') continue;
    $name = substr($line, 0, 46);
    $amount = substr($line, 46, 10);
    $name = rtrim(ltrim($name), " .");
    $amount = (float) str_replace(",", "", $amount);
    echo $name . ", " . $amount;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...