Я пытаюсь проанализировать файл с похожими строками:
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
Какие-либо предложения?
Этот шаблон захватывает имя, находя последовательность точек после имени.
Затем фиксирует число и запятую в качестве числа.
Затем я создаю новый массив и заменяю запятую ничем.
$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"}
Вы можете достичь этого с помощью UNGREEDY regexp.
Здесь, когда мы ловим имя, мы хотим «последовательность любого символа, за которой следует последовательность точек и пробелов». Итак, вот эквивалентное регулярное выражение: (.+)[. ]*
,
Но двигатель установлен в жадный режим по умолчанию. Что случится? Первая часть (.+)
не остановится ни на первой точке, ни на первой найденной пробел. Зачем? Потому что можно выполнить все регулярные выражения до конца строки, и движок пойдет по этому пути, как в жадном режиме.
То же самое относится ко всему регулярному выражению, которое вы можете увидеть в рабочем коде ниже. Первая группа захвата будет захватывать за пределами поля имени.
Мы должны сказать ему «съесть» менее подходящую часть.
<?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 "</pre>";
?>
Результат:
John David James (DEM),7808
Marvin D. Scott (DEM),6548
Maria "Mary" Williams (DEM),4551
Dwayne R. Johnson,4322
WRITE-IN,188
Если данные выровнены по столбцам (все столбцы имеют фиксированную ширину), используйте строковые функции, такие как 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;
}