多行PHP上的数字的正则表达式

时间:2013-11-29 19:18:48

标签: php regex

我有一个看起来像这样的文件(是的,换行符是正确的):

39                                              9
30 30 30 31 34 30 30 32 33 32 36 30 31 38 0D 0A 00014002326018..
39 30 30 30 31 34 30 30 32 33 32 36 30 35 34 0D 900014002326054.
0A                                              .
39 30 30 30 31 34 30 30 32 33 32 36 30 39 31 0D 900014002326091.
0A                                              .
39 30 30 30 31 34 30 30 32 33 32 36 31 36 33 0D 900014002326163.
0A                                              .
39                                              9
30 30 30 31 34 30 30 32 33                      000140023
32 36 32 30 30 0D 0A                            26200..
39                                              9
30 30 30 31 34 30 30 32 33 32 36 32 30 30 0D 0A 00014002326200..
39 30 30 30 31 34 30 30 32 33 32 36 31 32 32 0D 900014002326122.
0A                                              .
39                                              9
30 30 30 31 34 30 30 32 33                      000140023
32 36 31 35 34 0D 0A                            26154..
39 30 30 30 31 34 30 30 32 33                   9000140023
32 36 31 33 31 0D 0A                            26131..
39                                              9
30 30 30 31 34 30 30 32 33                      000140023
32 36 31 30 34 0D 0A                            26104..
39 30 30 30 31 34 30 30 32 33 32 36 30 39 30 0D 900014002326090.
0A                                              .
39 30 30 30 31 34 30 30 32 33 32 36 31 39 37 0D 900014002326197.
0A                                              .
39                                              9
30 30 30 31 34 30 30 32 33 32 36 32 30 38 0D 0A 00014002326208..
39 30 30 30 31 34 30 30 32 33                   9000140023
32 36 31 31 35 0D 0A                            26115..
39                                              9
30 30 30 31 34 30 30 32 33                      000140023
32 36 31 36 34 0D 0A                            26164..
39                                              9
30 30 30 31 34 30 30 32 33                      000140023
32 36 30 31 36 0D 0A 39 30 30 30 31 34 30 30 32 26016..900014002
33                                              3
32 36 32 34 36 0D 0A                            26246..
39                                              9
30 30 30 31 34 30 30 32 33                      000140023
32 36 32 34 36 0D 0A                            26246..
39                                              9
30 30 30 31 34 30 30 32 33                      000140023
32 36 30 37 39 0D 0A                            26079..
39                                              9
30 30 30 31 34 30 30 32 33                      000140023
32 36 31 32 30 0D 0A                            26120..
39                                              9
30 30 30 31 34 30 30 32 33 32 36 32 32 38 0D 0A 00014002326228..
39 30 30 30 31 34 30 30 32 33                   9000140023
32 36 31 38 36 0D 0A                            26186..

我有这个代码来抓取EID标签(以9000开头的数字),但我无法弄清楚如何让它做多行。

$data = file_get_contents('tags.txt');

$pattern = "/(\d{15})/i";

preg_match_all($pattern, $data, $tags);
$count = 0;
foreach ( $tags[0] as $tag ){

    echo $tag . '<br />';
    $count++;
}

echo "<br />" . $count . " total head scanned";

例如,第一行和第二行应该返回900014002326018而不是忽略第一行和第二行

我对正则表达式并不擅长,所以如果你能解释一下,我就会学习并且不必让别人用简单的正则表达式帮助我,那就太棒了。

编辑:整数是从9000开始的15位数

3 个答案:

答案 0 :(得分:6)

你可以这样做:

$result = preg_replace('~\R?(?:[0-9A-F]{2}\h+)+~', '', $data);
$result = explode('..', rtrim($result, '.'));

模式细节:

\R?            # optional newline character
(?:            # open a non-capturing group
  [0-9A-F]{2}  # two hexadecimal characters
  \h+          # horizontal white characters (spaces or tabs)
)+             # repeat the non-capturing group one or more times

更换后,您必须删除的唯一内容是两个点。删除尾随点后,您可以使用这些将字符串分解为数组。

另一种方式

由于您知道整数(和点)部分之前总共有48个字符,因此您也可以使用此模式:

$result = preg_replace('~(?:^|\R).{48}~', '', $data);

没有正则表达式的另一种方法

这个想法是逐行读取文件,因为内容之前的长度总是相同的(即16 * 3个字符 - > 48个字符),用整数提取子字符串并将其连接到{ {1}}临时变量。

$data

注意:如果文件具有Windows格式(行尾为ini_set("auto_detect_line_endings", true); $data = ''; $handle = @fopen("tags.txt", "r"); if ($handle) { while (($buffer = fgets($handle, 128)) !== false) { $data .= substr($buffer, 48, -1); } if (!feof($handle)) { echo "Error: fgets() has failed\n"; } fclose($handle); } else { echo "Error opening the file\n"; } $result = explode ('..', rtrim($data, '.')); ),则必须将\r\n函数的第三个参数更改为substr()。如果您对如何检测换行类型感兴趣,可以查看this post

答案 1 :(得分:4)

我认为甚至不可能使用单个正则表达式执行此操作,但如果您一次只执行此步骤,则您的代码将更易读和可维护。

这很有效,并且要弄清楚它是如何工作的应该不会太难:

$eid_tag_src = <<<END_EID_TAGS
39                                              9
30 30 30 31 34 30 30 32 33 32 36 30 31 38 0D 0A 00014002326018..
39 30 30 30 31 34 30 30 32 33 32 36 30 35 34 0D 900014002326054.
  :
 etc.
  :
39 30 30 30 31 34 30 30 32 33                   9000140023
32 36 31 38 36 0D 0A                            26186..
END_EID_TAGS;

/* Remove hex data from first 48 characters of each line */
$eid_tag_src = preg_replace('/^.{48}/m','',$eid_tag_src);

/* Remove all white space */
$eid_tag_src = preg_replace('/\s+/','',$eid_tag_src);

/* Replace dots (CRLF) with spaces */
$eid_tag_src = str_replace('..',' ',$eid_tag_src);

/* Convert to array of EID tags */
$eid_tags = explode(' ',trim($eid_tag_src));

print_r($eid_tags);

这是输出:

Array
(
    [0] => 900014002326018
    [1] => 900014002326054
    [2] => 900014002326091
    [3] => 900014002326163
    [4] => 900014002326200
    [5] => 900014002326200
    [6] => 900014002326122
    [7] => 900014002326154
    [8] => 900014002326131
    [9] => 900014002326104
    [10] => 900014002326090
    [11] => 900014002326197
    [12] => 900014002326208
    [13] => 900014002326115
    [14] => 900014002326164
    [15] => 900014002326016
    [16] => 900014002326246
    [17] => 900014002326246
    [18] => 900014002326079
    [19] => 900014002326120
    [20] => 900014002326228
    [21] => 900014002326186
)

答案 2 :(得分:1)

这是一种使用有效抓取(无需替换)的方法:

RegEx /(?:^.{48}|\.)([0-9]+\.?)/m - explained demo

这意味着(用简单的英语):从行的开头开始抓取数字后跟一个可选的点 IF ,前面有48个字符 OR a点(特例)。

您的代码可能如下所示:

$pattern = '/(?:^.{48}|\.)([0-9]+\.?)/m'; 

preg_match_all($pattern, $data, $tags);

//join all the bits belonging to the number
$data=implode("", $tags[1]); 

//count the dots to have a correct count of the numbers grabbed
//since each number was grabbed with an ending dot initially
$count=substr_count($data, ".");

//replace the dots with a html <br> tag (avoiding a split and a foreach loop)
$tags=str_replace('.', "<br>", $data); 

print $tags . "<br>" . $count . " total scanned";

查看http://3v4l.org/Z4EhI

上的代码