【问题标题】:Can't match regex with sed无法将正则表达式与 sed 匹配
【发布时间】:2016-12-30 09:40:04
【问题描述】:

我正在尝试将模式 (\^|\~?)(\d|x|\*)+\.(\d|x|\*)+\.(\d|x|\*)+sed 匹配,但没有运气。 我正在运行的文件是这样的:

{
  "name": "something",
  "version": "0.0.1",
  "description": "some desc",
  "main": "gulpfile.js",
  "directories": {
    "test": "tests"
  },
  "dependencies": {
    "babel-polyfill": "^6.7.4",
    "babel-preset-es2015": "^6.6.0",
    "babel-preset-react": "^6.5.0",
    "gulp-clean": "^0.3.2",
    "jquery": "^2.1.4",
    "lodash": "^4.0.0",
    "moment": "^2.13.0",
    "moment-timezone": "^0.5.0",
    "radium": "^0.16.2",
    "react": "^15.1.0",
    "react-bootstrap-sweetalert": "^1.1.10",
    "react-dom": "^15.1.0",
    "react-timeago": "^2.2.1",
    "sprintf": "^0.1.5",
    "smoothscroll": "~0.2.2"
  },
  "devDependencies": {
    "babel": "^6.3.26",
    "babelify": "^7.2.0",
    "browserify": "~12.0.1",
    "console-stamp": "^0.2.0",
    "estraverse-fb": "^1.3.1",
    "gulp": "^3.9.0",
    "gulp-concat": "^2.6.0",
    "gulp-sass": "^2.1.1",
    "gulp-sourcemaps": "^1.6.0",
    "gulp-util": "^3.0.7",
    "lodash": "4.5.1",
    "lodash.assign": "^3.2.0",
    "lodash.isfunction": "^3.0.8",
    "lodash.reduce": "^4.3.0",
    "node-sass": "3.4.2",
    "react-bootstrap": "^0.29.4",
    "react-intl": "2.1.0",
    "reactify": "1.1.1",
    "sweetalert": "^1.1.3",
    "vinyl": "^1.1.0",
    "vinyl-buffer": "^1.0.0",
    "vinyl-source-stream": "^1.1.0",
    "watchify": "^3.4.0",
    "jsx-to-string": "~0.2.11"
  },
  "optionalDependencies": {
    "pkg-save": "~1.0.2"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "someurl"
  },
  "author": "authorname",
  "license": "MIT"
}

正如您在 regexr 中看到的,它匹配所需的模式(也匹配“版本”,但这是我稍后会解决的另一个问题): http://regexr.com/3e324

我正在使用以下命令调用 sed:
cat package.json | sed 's/(\^|\~?)(\d|x|\*)+\.(\d|x|\*)+\.(\d|x|\*)+/Hello/g' -r

为简洁起见,它输出类似(即未过滤的输入):

...
"dependencies": {
    "babel-polyfill": "^6.7.4",
    "babel-preset-es2015": "^6.6.0",
    "babel-preset-react": "^6.5.0",
    "gulp-clean": "^0.3.2",
...

它应该用“Hello”替换所有数字。
我做错了什么?
与坏标志有关(我试过 /gm
还是没有使用正确的正则表达式引擎(我通过-r 选项来使用扩展正则表达式)?

【问题讨论】:

  • 我不知道您的sed 问题的答案(抱歉),但我只想提一下,如果您正在做一些这样的 JSON 工作,您可能想要使用更适合的工具就像jq
  • 谢谢,这可能是我需要的!我需要一个可以直接操作 package.json 文件的工具,并且我可以完全控制正在更改的内容。
  • 我已通过使用[0-9] 而不是\d 来修复它。 (如果您处理大量 JSON,我仍然第二次使用 jq
  • 太好了,谢谢@Aaron。我认为传递 -r 将使 sed 能够识别 \d 字符类。我想我会继续使用jq 以获得更好的操作。随意写一个答案,我会将其标记为已批准。
  • 所有工具都使用具有不同警告/约束的不同正则表达式风格。使用一些在线正则表达式验证器是没有用的,因为它不能保证给定的正则表达式将在您想要使用它的任何工具中工作。

标签: regex bash replace sed


【解决方案1】:

虽然 POSIX 正则表达式支持某些命名字符类,例如 [[:digit:]][[:alnum:]],但它们不支持速记类,例如 \d\w

根据regular-expressions.info,一些 GNU 扩展支持速记类,但仅限于其中的几个,\w\W\s\S

通过将正则表达式中的\d 替换为[0-9],我能够转换您的文档。正则表达式变为(\^|\~?)([0-9]|x|\*)+\.([0-9]|x|\*)+\.([0-9]|x|\*)+,或者更好的[~^]([0-9x*]+\.){2}[0-9x*](感谢 Ed Morton!)。

附带说明,您的命令可以重写为以下内容,不使用 cat

sed -E 's/[~^]([0-9x*]+\.){2}[0-9x*]/Hello/' package.json

正如 Matt 所说,您最好使用 JSON 解析器,例如 jq

【讨论】:

  • 您的脚本目前是 GNU sed 特定的,因为 -r 而不是 -E 以启用 ERE,并且您正在转义不需要转义的字符,例如~ 和像 ([0-9]|x|\*)+ 这样的 RE 段不必要地冗长/复杂,等等。我知道那是因为你复制了 OP 不起作用的脚本,但最好把它清理干净——整个事情可以写得更多便携(未经测试,但如果不完全正确,将接近)sed -E 's/[~^]([0-9x*]+\.){2}[0-9x*]/Hello/'.
  • 谢谢,我已经测试过了(虽然使用 GNU sed)并更新了我的答案。我不知道-E 存在,它甚至没有出现在我的man sed 中!
  • 是的。它在 BSD sed 和较新的 GNU seds 中被支持作为 -r 的替代方案,但 GNU 人员[尚未] 更新文档。
猜你喜欢
  • 2020-09-17
  • 2018-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-17
  • 2020-11-14
  • 2014-09-06
  • 1970-01-01
相关资源
最近更新 更多