【问题标题】:Handling text file with unknown newline positions处理具有未知换行位置的文本文件
【发布时间】:2012-09-06 16:14:37
【问题描述】:

我的问题很简单:我有一个文本文件,我处理并插入数据库中的所有数据,并为每个新行处理它。问题是文本文件是在我的网关中接收到的短信的日志,并且根据正在发送的文本,我将有一行对应于每个短信。如果 SMS 在其正文中没有任何新行,则一切正常,另一方面,如果 SMS 是这样发送的:

"Test 
TestOnANewLine" 

我得到一个中断的日志文件,每次都换行。示例如下:

2012-01-01 10:10:10,4C64DCD6.req,192.168.999.999,+12223334444,OK -- SMPP - 999.999.999.999:9999,SubmitUser=user;Sender=sender;SMSCMsgId=999999999;Text="Test1
NewLineTest
AnotherNEwLineTEst"

日志文件解释如下:

date time, smsid, ip that processed it, number that is being sent to, status --connection type - ip that is sent from, user that submitted; sender name that is displayed; sms connection id; body of the sms 

至于我使用 PHP 的语言和使用的函数,它很简单

    foreach($lines as $line)
        {    explode and do stuff   }

我该如何处理这种情况?在这一点上,任何帮助表示赞赏

提前致谢!!

【问题讨论】:

  • 如果 SMS 包含 " 字符会怎样?这如何与现场引用进行转义/区分?
  • 这就是问题所在,它可能在正文中有一个 " 字符。
  • @gjermani 请不要编辑您的问题以包含答案。您可以为自己的帖子创建一个答案,以与 Stackoverflow 的问答格式保持一致。
  • @MathieuImbert 谢谢你的提示,完成了:) 正如你所见,我在这里很新
  • @gjermani 没问题。我对您的编辑进行了回滚,并改进了您答案中的格式。您可以使用 4 个空格缩进来格式化代码块,而不是使用 `<br> 标记。

标签: php mysql file text newline


【解决方案1】:

fgetcsv 可以处理包含在 '"' 中的换行符,但在正文中添加一个额外的 '"' 字符会失败...

那么一些不负责任的regexp 用法呢?

preg_match_all(#^(\d{4}-\d{2}-\d{2}[^,]+),([^,]+),([^,]+),([^,]+),([^,]+),SubmitUser=([^;])+;Sender=([^;])+;SMSCMsgId=([^;])+;Text="([\w\d\s\.\-,:;'"]+)"$#im', $file, $matches);

应该做的工作,不是太疯狂的文本,也许你应该使用 \w\d\s.-,:;'" 表达更符合你的需要

【讨论】:

  • 我不太清楚如何实现这一点,但我会弄清楚的。谢谢!
  • 我以前从未听说过这些功能,所以请原谅我的无知:D
  • 感谢您的回复,最后我使用了file_get_contents,当然我将我的解决方案发布为编辑
【解决方案2】:

难道你不能循环遍历换行符直到你可以从中解析出一个日期吗? 也许考虑到前一行以双引号结尾?

我知道它不是万无一失的,但没有一些可识别的“消息结束”字符。这是我能想到的最好的:P

【讨论】:

  • 我喜欢你的想法 - 并使用了它!我会给你一个投票,但我显然没有足够的声誉:P
【解决方案3】:

首先,感谢您的所有反馈,它真的很宝贵,它帮助我解决了这个问题。另外,对于所有将阅读这篇文章并希望在这里找到解决方案的人来说,这是我的:

我将解释行尾 /r/n 的方式从常规行更改为 /r/n2,这意味着当且仅当有常规新行 /r/n并且在新的实体线上有一个2(这是年初)

实际解决的部分是:

$data = file_get_contents($backup_file);
$lines=explode("\r\n2",$data);
foreach($lines as $line)
{
  //explode and do stuff
}

【讨论】:

    【解决方案4】:

    尝试将所有日志条目规范化为每个日志条目的单个数组项(即将多个换行符的条目组合成一个条目)

    $line_array = file('/path/to/file');
    $log_array = array();
    
    $i = -1;
    $date_pattern = '/^[0-9]{4}-[0-9]{2}-[0-9]{2}\s[0-9]{2}:[0-9]{2}:[0-9]{2}/';
    foreach ($line_array as $line) {
        if (1 === preg_match($date_pattern, $line)) {
            // this is a new log entry
            // let's trim the whitespace from the end of the last log array entry since we are done with it 
            if(isset($log_array[$i])) {
                $log_array[$i] = rtrim($log_array[$i]);
            }
    
            // start a new log array entry
            $i++;
            $log_array[$i] = $line;
        } else {
            // this is not a new log entry
            $log_array[$i] .= $line;
        }
    }
    

    之后,您应该能够使用$log_array 来提取您需要的数据。顺便说一句,我应该注意到,当您循环访问 $log_array 时。首先提取味精文本可能会有所帮助。如果你在双引号上做一个贪婪的preg_match,你不应该对包含引号的消息有任何问题,因为贪婪匹配会找到最大可能的匹配字符串,在你的情况下,这将是引号边界之间的所有内容消息内容。

    【讨论】:

    • 嗯,很有趣,非常感谢 - 我会试一试,然后告诉你:)
    • 谢谢迈克。我最终使用了file_get_contents 和一个简单的爆炸 - 我将我的解决方案发布为编辑
    • @gjermani 这种方法应该可行,但您可能需要考虑扩展而不仅仅是在下一行中查找“2”,因为人们经常在短信中使用“2”,所以你有一个新日志条目误报的可能性更高。
    • 你是对的,我的方法并非万无一失,但由于修复受到时间的限制(如您所知:截止日期截止日期是您从经理口中听到的唯一一句话)我去了对于这个修复
    • 我只是开始遵循你的这种方法 - 将来会尝试使用它
    猜你喜欢
    • 1970-01-01
    • 2020-06-08
    • 1970-01-01
    • 2014-05-21
    • 2016-05-15
    • 1970-01-01
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    相关资源
    最近更新 更多