【问题标题】:perl style regex mysqldump column definitionperl 风格正则表达式 mysqldump 列定义
【发布时间】:2016-04-29 08:35:17
【问题描述】:

我正在尝试修复 php-mysql-diff 中关于解析 mysqldump 列定义的错误。

这些工具可以正确解析如下行:

`version_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`ucm_item_id` int(10) unsigned NOT NULL,
`ucm_type_id` int(10) unsigned NOT NULL,
`version_note` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT 'Optional version name',

但是在 cmets 中有 ;(分号)或 /(斜线)的行上会失败

`keep_forever` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0=auto delete; 1=keep',

原来的部分正则表达式是

'\((?<tableDefinition>[^;\/]+)\)';

请参阅RegExPattern.php:35,我将其理解为“任何不是 ; 或 / 的东西”

我想将其扩展为:“任何不是 ; 或 / 的东西,除非它在一对 ' 内”(单勾)

我试着这样表达:

([^;\/]+(COMMENT\s\'[^\']+\')?)+[^;\/]*?

可以解释为“重复 |no ; 或 /| 后跟一个可选的 DDL COMMENT 至少一次后跟一组可选的 |no ; 或 /|”

但是,即使我尝试了许多类似的变体,我也无法解析上面的列

除此之外,注释还可以包含单引号作为“''”(两个单引号)。我之前应用过这个

\'([^\']+|\'\'))\'

(见commit) 这也需要以某种方式整合到答案中

参考:匹配表和列的原始代码:

/**
 * @return string
 */
public static function tables()
{
    $pattern = '/(?<creationScript>CREATE\s+TABLE\s+`(?<tableName>\S+)`\s+';
    $pattern .= '\((?<tableDefinition>[^;\/]+)\)';
    $pattern .= '(?:\s+ENGINE=(?<engine>[^;\s]+))?\s*';
    $pattern .= '(?:AUTO_INCREMENT=(?<autoIncrement>\d+))?\s*';
    $pattern .= '(?:DEFAULT CHARSET=(?<defaultCharset>[^;\s]+))?\s*)';
    $pattern .= '(?:COLLATE=.+?)?\s*';
    $pattern .= '(?:\/\*.+?\*\/)?\s*';
    $pattern .= ';/';
    $pattern .= 's'; // modifier
    return $pattern;
}
/**
 * @return string
 */
public static function column()
{
    $pattern = '/\s*';
    $pattern .= '`(?<columnName>\S+?)`\s+';
    $pattern .= sprintf('(?<columnType>%s)\s*', implode('|', self::$columnTypeRegExps));
    $pattern .= '(?:CHARACTER SET\s+(?<characterSet>\S+))?\s*';
    $pattern .= '(?:COLLATE\s+(?<collate>\S+))?\s*';
    $pattern .= '(?<nullable>NULL|NOT NULL)?\s*';
    $pattern .= '(?<autoIncrement>AUTO_INCREMENT)?\s*';
    $pattern .= '(?:DEFAULT (?<defaultValue>\S+|\'[^\']+\'))?\s*';
    $pattern .= '(?:ON UPDATE (?<onUpdateValue>\S+))?\s*';
    $pattern .= '(?:COMMENT \'(?<comment>[^\']+)\')?\s*';
    $pattern .= '(?:,|$)/';
    return $pattern;
}

【问题讨论】:

  • 您到底想得到什么结果?你需要列名吗?我想到了一些(*SKIP)(*FAIL) 机制。要仅获取列名,(?P&lt;column&gt;[^`]+) 工作得很好(注意 `,它在 Stackoverflow 中被视为代码)。
  • 该工具只需要 preg_match_all 中的每一行作为进一步解析的结果。由于这个问题,我希望简单地匹配违规行。我不想重写库
  • 我已经添加了已经在使用的正则表达式来匹配表和列。我正在寻找修复与列定义作为一个整体匹配的表正则表达式部分
  • 您是否还需要处理空注释字符串和并列字符串文字等极端情况?
  • 我想不会有什么坏处。我今天找到了这个工具,作者和我肯定会感谢任何改进

标签: php sql regex parsing mysqldump


【解决方案1】:

你可能要特地迎合cmets:

评论模式的修改:

(COMMENT\s\'[^\']+((\'\')+[^\']*)*\')?

tableDefinition模式的修改:

\((?<tableDefinition>([^;\/]+?(.COMMENT.'[^']+(('')[^']*)*'(?!=')))+.*?|[^;\/]+?)\)

【讨论】:

  • 感谢您的快速回复。我不知道 &comment 是如何工作的,我应该粘贴这条正则表达式行并尝试吗?
  • 你的表达式有错误,应该是:'\((?&lt;tableDefinition&gt;[^;\/]+(&amp;comment[^;\/]+)*)\)';(注意tableDefinition后面的左括号)。
  • 我成了 perl 和 php regexen 之间细微差别的牺牲品。 @简谢谢;纠正
  • 这对我来说似乎合乎逻辑,但不知何故失败了,介意在聊天中看看这个吗?
  • 只是看着我自己。向前和向后 ping 10 cmets 将推荐一个
猜你喜欢
  • 2011-02-05
  • 1970-01-01
  • 2011-09-24
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多