V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
helloiac
V2EX  ›  问与答

正则做不到这个是吧?

  •  
  •   helloiac · 2018-08-03 12:09:46 +08:00 · 2898 次点击
    这是一个创建于 2305 天前的主题,其中的信息可能已经有所发展或是发生改变。

    匹配字符串: <sometag>一些任意不定长的文字,但不包括 AT 符号和小于号</sometag>

    一步将其替换为: <sometag>一 @些 @任 @意 @不 @定 @长 @的 @文 @字 @,@但 @不 @包 @括 @A@T@符 @号 @和 @小 @于 @号</sometag>

    也就是在 tag 内部的任意两个字符之间插入 @ 。

    我想了下应该是做不到的,请大家帮确认下。

    第 1 条附言  ·  2018-08-03 13:38:07 +08:00
    此问题的应用场景是一个大约 5M 的 shell 脚本,这个 shell 脚本是一系列 sed 替换语句的集合,sed 替换规则中全部是正则。

    只考虑用正则是因为:
    1、这个脚本是由其它一堆 shell 脚本生成的,维护不是很“直接”
    2、shell 的函数功能比较弱,复杂些的也不好维护
    3、引入函数可能急剧增加运行时间
    22 条回复    2018-08-05 12:10:31 +08:00
    thedog
        1
    thedog  
       2018-08-03 12:31:13 +08:00 via Android
    当成一个列表,join 一下?不明白为什么要用正则
    jayx
        2
    jayx  
       2018-08-03 12:33:43 +08:00
    python 零宽断言匹配,然后 join()方法插入
    CEBBCAT
        3
    CEBBCAT  
       2018-08-03 12:49:37 +08:00
    正则把 sometag 匹配出来,别的事交给我 C 来做
    dreasky
        4
    dreasky  
       2018-08-03 13:11:51 +08:00
    re.sub(r'(.)', r'@\1', r'一些任意不定长的文字,但不包括 AT 符号和小于号')
    '@一 @些 @任 @意 @不 @定 @长 @的 @文 @字 @,@但 @不 @包 @括 @ @A@T@ @符 @号 @和 @小 @于 @号'

    中文需要 python3,剩下的问题很简单
    rabbbit
        5
    rabbbit  
       2018-08-03 13:23:41 +08:00
    硬写成一行倒是可以 js
    text = '<sometag>一些任意不定长的文字,但不包括 AT 符号和小于号</sometag>';
    text.replace(/(?<=<sometag>)(.*)(?=<\/sometag>)/, (str) => {return str.split('').filter(function(i) { return i.trim() !== '' ? true: false}).join('@')});
    // "<sometag>一 @些 @任 @意 @不 @定 @长 @的 @文 @字 @,@但 @不 @包 @括 @A@T@符 @号 @和 @小 @于 @号</sometag>"
    rabbbit
        6
    rabbbit  
       2018-08-03 13:25:45 +08:00
    更正
    text.replace(/(?<=<sometag>)(.*)(?=<\/sometag>)/, (str) => {return str.split('').filter((i) => { return i.trim() !== ''}).join('@')});
    helloiac
        7
    helloiac  
    OP
       2018-08-03 13:40:27 +08:00
    @dreasky 谢谢。因为待匹配文本是不确定的,且有 tag 包裹这个 context 限定,所以恐怕这个方案不可行。
    ragnaroks
        8
    ragnaroks  
       2018-08-03 13:42:00 +08:00   ❤️ 1
    有个文本处理问题,他想到用正则来解决,现在他有两个问题了
    helloiac
        9
    helloiac  
    OP
       2018-08-03 13:42:15 +08:00
    @thedog 谢谢,APPEND 了信息,没有类似 join 的函数可用,且效率太低。
    ragnaroks
        10
    ragnaroks  
       2018-08-03 13:43:22 +08:00
    如果是每个字符后加 at 的话,我的想法是创建个 2 倍字符数的数组,遍历进去..
    helloiac
        11
    helloiac  
    OP
       2018-08-03 13:44:15 +08:00
    @CEBBCAT 是不是正则匹配出来,暂存到变量,更改后再 replace 回去呀?
    helloiac
        12
    helloiac  
    OP
       2018-08-03 13:45:58 +08:00
    @rabbbit 谢谢具体方案,用比较高级的语言的话这个方案挺好的,不过我用的是 shell,sed 也不支持零宽断言。
    yyfearth
        13
    yyfearth  
       2018-08-03 13:51:45 +08:00   ❤️ 1
    @helloiac 正则一次找不到 但是两次应该可以做到
    先把 tag 里面的内容抓出来 然后替换里面的内容 每个字后面中间加 at (除了第一个字 每个字去买加 或者 除了最后一个 每个后面加)

    @rabbbit 都用上 箭头了 为啥还要用 return 另外可以不用 filter
    text.replace(/(?<=<sometag>)(.*)(?=<\/sometag>)/, str => str.split(/\s*/).join('@'))

    另外这个用到了最新的 ES RegExg 的功能 "?<=" 其实不用也可以
    text.replace(/(<sometag>)(.*)(?=<\/sometag>)/, (a, b, str) => b + str.split(/\s*/).join('@'))
    JmmBite
        14
    JmmBite  
       2018-08-03 13:58:19 +08:00
    ```ruby
    '<tag>一些任意不定长的文字,但不包括 AT 符号和小于号</tag>'.gsub(/(?<!>)([^\@\>\<\s])/, " @\\1")

    => "<tag>一 @些 @任 @意 @不 @定 @长 @的 @文 @字 @, @但 @不 @包 @括 @A @T @符 @号 @和 @小 @于 @号</tag>"
    ```
    FanWall
        15
    FanWall  
       2018-08-03 14:10:15 +08:00 via Android
    正则很容易做到,但如果不支持环视就无法一句搞定。
    helloiac
        16
    helloiac  
    OP
       2018-08-03 15:17:56 +08:00
    @JmmBite 在 irb 运行了一下,结果跟你的不一样。

    irb(main):004:0> '<tag>abcdefg</tag>'.gsub(/(?<!>)([^\@\>\<\s])/, " @\\1")
    => "< @t @a @g>a @b @c @d @e @f @g< @/ @t @a @g>"
    CEBBCAT
        17
    CEBBCAT  
       2018-08-03 16:25:27 +08:00
    @helloiac #11 输入输出流分开,加了'@'的文本直接写到另一个文件里去
    goofool
        18
    goofool  
       2018-08-03 18:37:03 +08:00
    瞎写
    sed """ /<.*>/{h; s/\(<[^\/]*>\).*/\1/p;g;s/<.*>\(.*\)<\/.*>/\1/;s/\(.\)/\1@/g; s/@$//p;g;s/.*\(<\/.*>\)/\1/p;d;}; p """ test.txt
    rabbbit
        19
    rabbbit  
       2018-08-04 02:46:06 +08:00
    @yyfearth
    你记忆力真好啊,我就记不住这么多用法细节
    hundan
        20
    hundan  
       2018-08-04 12:45:02 +08:00
    @FanWall 怎么做呢,想了想感觉用环视也做不出
    helloiac
        21
    helloiac  
    OP
       2018-08-05 12:06:24 +08:00
    @CEBBCAT 这个脚本中是一系列管道串起来的 sed, 很多行都是要运行这个的。你说的写到另一个文件里是什么意思?
    helloiac
        22
    helloiac  
    OP
       2018-08-05 12:10:31 +08:00
    @hundan
    @FanWall 是的,我也不明白用环视怎么解决。
    我认为根本问题是待匹配对象不定长,而正则替换又不能将 [量词表达的捕获组] 循环处理。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1049 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 18:39 · PVG 02:39 · LAX 10:39 · JFK 13:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.