-12

在 Casimir et Hippolyte 的帮助下,我一直在尝试解析一些文本,如下例所示(注意:我的原始问题过度简化了示例文本 - 因为我认为我很容易能够将提供的任何解决方案调整为实际文本。然而,在用手指敲击钥匙和敲击墙壁之后,我仍然没有更聪明)。

这是我到目前为止所拥有的......我已经尝试转义数据(addslashes),但我认为我会以原始(er)形式发布$subject......

<?php

$subject = "
Ydqk‚_,¦#¦#À%¦#¦#¦#¦#¦#èeèe2%Ž¦#¦#¦#Cf¦#¦#¦#¦#qk¦#¦#¦#¦#¦#¦#¦#¦#¦#Ð     ð:SOME COMPANY<br />
WITH A LONG NAME<br />
The Big Barn, 23 London Lane, Cheltenham, Glos. GL1 1GL<br />
Tel. 022234 567890 Fax. 02234 345678 Email.  <a href= mailto:info@some.co.uk </a>info@some.co.uk<br />
Company: Another Company (AKA) – 22 London Lane, Cheltenham, GL1 2GL<br />
FAO: Mr D. Mistify/ A. Clarity/ Jo Bloggs<br />
PROJECT OMAHA   <br />
    <br />
    <br />
    CONTRACT No.    14  DATE    10/6/13 <br />
    No. QUESTION    ANSWER  <br />
    <br />
973 <br />
Hi, it's me again:<br />
I'm very, very confused. Why do regular expressions seem such a dark art?<br />
Surely it can't be as hard as I manage to make it seem?<br />
Please advise<br />
Thank you.  <br />
Date Required – <br />
17/6/13 <br />
    <br />
Signed for and on behalf of Some Company with a Long Name Limited<br />
Me Again – Senior Moment<br />
________________________________________________________<br />
<br />
<br />
<br />
<br />
<br />
<br />
QUESTION / ANSWER SHEET<br />
Some Company with a Long Name<br />
<br />
Question and Answer System<br />
AA414<br />
’“¸¹ÉÊËÌÔ...descends into gibberish...
";

$pattern = '~
    Project\hNo\.\h\d++\hDATE\h
    (?<date>\d{1,2}\/\d{1,2}\/\d{1,2})
    \s++No\.\hQUESTION\hANSWER\s++
    (?<No>\d++)\s++

    # all characters but D or D not followed by "ate Required"
    (?<desc>(?>[^D]++|D(?!ate\hRequired))+)

    \D++
    (?<date_required>\d{1,2}\/\d{1,2}\/\d{1,2})
~x';

preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);

print_r($matches);

?>

我想提取以下内容:

  • 发布日期 (10/6/2013) (dd/mm/yyyy)
  • 问题编号 (973)
  • 说明
  • 所需日期 (17/6/2013) (dd/mm/yyyy)
4

1 回答 1

1

$subject这个想法是通过不使用点(是你的字符串)来避免新行的问题:

$pattern = '~
    Project\hNo\.\h\d++\hDATE\h
    (?<date>\d{1,2}\/\d{1,2}\/\d{1,2})
    \s++No\.\hQUESTION\hANSWER\s++
    (?<No>\d++)\s++

    # all characters but D or D not followed by "ate Required"
    (?<desc>(?>[^D]++|D(?!ate\hRequired))+)

    \D++
    (?<date_required>\d{1,2}\/\d{1,2}\/\d{1,2})
~x';

preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);

print_r($matches);

请注意,我使用所有格量词原子组来避免尽可能回溯

编辑:

根据您的新示例字符串,我为您提供了一种更具可读性和可编辑性的新型模式(以一种 lex 样式):

$pattern = <<<LOD
~
 # Raw types
 (?(DEFINE)(?<uint>  \d++                      ))
 (?(DEFINE)(?<date>  \d{1,2}\/\d{1,2}\/\d{1,2} ))

 # Custom types
 (?(DEFINE)(?<void>  (?>\s++|<br\b[^>]*+>)*           ))
 (?(DEFINE)(?<desc>  (?>[^D]++|D(?!ate\h++Required))+ ))

 # Anchors
 (?(DEFINE)(?<A_prj_date>      PROJECT(?>[^D]++|D(?!ATE\b))+DATE\h*+    ))
 (?(DEFINE)(?<A_prj_number>    \g<void>No\.\h++QUESTION\h++ANSWER\b\D++ ))
 (?(DEFINE)(?<A_prj_desc>      \g<void>                                 ))
 (?(DEFINE)(?<A_prj_date_req>  Date\h++Required\D++                     ))

 # Pattern
 \g<A_prj_date>     (?<prj_date>      \g<date> )
 \g<A_prj_number>   (?<prj_number>    \g<uint> )
 \g<A_prj_desc>     (?<prj_desc>      \g<desc> )
 \g<A_prj_date_req> (?<prj_date_req>  \g<date> )    

~xi
LOD;

它从您需要的每个组件的定义开始。

  1. 原始类型:随处可见的子模式
  2. 自定义类型:特定于您的项目的子模式
  3. 锚点:描述必填字段之间转换的子模式

之后,您将拥有由这些元素组成的模式本身。

您可以获得高度可编辑的内容,因为您可以根据需要调整所有子模式,添加新的子模式并与其他人组合新的子模式。

例如,您可以尝试将A_prj_number子模式替换\D++为对您的示例字符串来说似乎足够好的子模式:

(?(DEFINE)(?<A_prj_number>\D++))

这种语法的另一个优点是,您可以轻松地调试您的模式,从最后一个到第一个元素(在模式部分中)逐个注释,直到获得匹配:

# Pattern
 \g<A_prj_date>     (?<prj_date>      \g<date> )
 \g<A_prj_number>   (?<prj_number>    \g<uint> )
 # \g<A_prj_desc>     (?<prj_desc>      \g<desc> )
 # \g<A_prj_date_req> (?<prj_date_req>  \g<date> ) 

注意:如果您只有一个字符串项目,请使用preg_match而不是preg_match_all

于 2013-06-10T16:28:01.673 回答