V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wadezhao
V2EX  ›  Ruby on Rails

球写一段及其简单的 Ruby 代码

  •  
  •   wadezhao · 2016-12-08 17:20:29 +08:00 · 7431 次点击
    这是一个创建于 2667 天前的主题,其中的信息可能已经有所发展或是发生改变。

    用 Redmine 管理项目,是 Ruby 写的, Ruby 貌似在 Windows 下处理中文编码有点问题,导致 Redmine 中一些中文文件名的图片显示不正常,我找到解决方法但是不懂 Ruby ,请求帮忙。

    需求很简单,下面这个函数是对字符串进行处理,处理后的字符串差不多是这样: /attachments/download/455/02%E5%AE.jpg 我想把最后一个“/”后面的字符删除,就是返回是 /attachments/download/455/ 应该很简单吧,函数如下:

    def htmlesc( str, mode=:Quotes )
      if str
        str.gsub!( '&', '&' )
        str.gsub!( '"', '"' ) if mode != :NoQuotes
        str.gsub!( "'", ''' ) if mode == :Quotes
        str.gsub!( '<', '&lt;')
        str.gsub!( '>', '&gt;')
      end
      str
    end
    
    30 条回复    2016-12-09 15:44:52 +08:00
    wadezhao
        1
    wadezhao  
    OP
       2016-12-08 17:20:48 +08:00
    哦,忘记说谢谢了。

    谢谢。
    awolfly9
        2
    awolfly9  
       2016-12-08 17:23:18 +08:00
    用 / 分割字符串,然后去掉最后一个再把所有的子串连接,就是你想要的
    liprais
        3
    liprais  
       2016-12-08 17:23:45 +08:00
    str.split("/")[1..-2].join('') 这样?
    liprais
        4
    liprais  
       2016-12-08 17:24:12 +08:00
    @liprais str.split("/")[0..-2].join('') 更正一下
    liprais
        5
    liprais  
       2016-12-08 17:25:07 +08:00   ❤️ 1
    @liprais "/attachments/download/455/02%E5%AE.jpg".split("/")[0..-2].join("/")
    这下感觉对了,最近真是手酸.....
    Herobs
        6
    Herobs  
       2016-12-08 17:28:02 +08:00 via Android
    @liprais 虽然结果是对的,但是你不觉得做了很多无用功吗
    liprais
        7
    liprais  
       2016-12-08 17:31:03 +08:00   ❤️ 2
    @Herobs
    "请尽量让自己的回复能够对别人有帮助"
    lightening
        8
    lightening  
       2016-12-08 17:33:05 +08:00   ❤️ 1
    更推荐用自带的 helper 。

    > File.dirname('/attachments/download/455/02%E5%AE.jpg')
    => # "/attachments/download/455"

    如果想加 "/" 就

    > File.dirname('/attachments/download/455/02%E5%AE.jpg') + "/"
    Jodal
        9
    Jodal  
       2016-12-08 18:09:24 +08:00   ❤️ 1
    Jodal
        10
    Jodal  
       2016-12-08 18:11:54 +08:00
    最好还是使用 File 的方法,因为文件名有可能空格之类的,虽然我写的正则包含了 233 (笑
    wadezhao
        11
    wadezhao  
    OP
       2016-12-08 19:27:22 +08:00
    @liprais 谢谢,不过我完全不懂 Ruby ,是把函数最后一行
    str
    换成
    str.split("/")[0..-2].join("/")
    么?貌似不行。


    @lightening 谢谢。见上,我把
    str
    换成
    File.dirname(str)+ "/"
    貌似不行……


    @Jodal 你这个我就完全看不懂了…………
    wadezhao
        12
    wadezhao  
    OP
       2016-12-08 19:31:00 +08:00
    @liprais
    @lightening
    还有一个可能,你们两个的方法都对,但是返回的字符串在别的地方还有处理,识别出了尾部不是图片扩展名,又对字符串做了一些操作,导致最终显示在页面里的内容不对,郁闷了,我这个完全不懂 Ruby 的人还得继续去摸索……
    lightening
        13
    lightening  
       2016-12-08 20:26:06 +08:00
    那你慢慢说,导致的不正常是怎么产生的。原来的图片 url 变成了什么?
    102400
        14
    102400  
       2016-12-08 22:05:23 +08:00   ❤️ 1
    "#{File.dirname('/attachments/download/455/02%E5%AE.jpg')}/"
    wadezhao
        15
    wadezhao  
    OP
       2016-12-08 22:10:21 +08:00
    @lightening
    嗯,谢谢。
    是这样,原始的代码,最终体现到页面上,是这样的:

    <img src="/attachments/download/455/02%E5%AE.jpg">

    但是这张图片并不显示,如果你直接点击这个图片,会提示一段 HTML 代码,说这个文件不存在,而不存的文件名,并不是"02%E5%AE.jpg",而是一个“乱码.jpg ”,换句话说,直接点击,会告诉你

    http://URL/attachments/download/455/乱码乱码乱码.jpg 不存在

    看上去,像是 Windows 下的 Ruby ,或者是源代码,对中文文件名的处理有一点问题。
    所以我就寻找解决方案,最彻底的方案当然是找到乱码的原因,不过这个不好找,我找了一个妥协的方案,那就是,我发现其实直接把文件名去掉的话,是能显示的,就是说

    <img src="/attachments/download/455/">

    是可以正常显示的。所以我就想,只要能找到生成这一段代码的 Ruby 源码,生成的字符串,将最后一个“/”之后的字符全删掉,不就行了么?
    于是我就找到了这一部分,这一部分的源码是这样的:

    def inline_textile_image( text )
    text.gsub!( IMAGE_RE ) do |m|
    stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8]
    htmlesc title
    atts = pba( atts )
    atts = " src=\"#{ htmlesc url.dup }\"#{ atts }"
    atts << " title=\"#{ title }\"" if title
    atts << " alt=\"#{ title }\""
    # size = @getimagesize($url);
    # if($size) $atts.= " $size[3]";

    href, alt_title = check_refs( href ) if href
    url, url_title = check_refs( url )

    out = ''
    out << "<a#{ shelve( " href=\"#{ href }\"" ) }>" if href
    out << "<img#{ shelve( atts ) } />"
    out << "</a>#{ href_a1 }#{ href_a2 }" if href

    if algn
    algn = h_align( algn )
    if stln == "<p>"
    out = "<p style=\"float:#{ algn }\">#{ out }"
    else
    out = "#{ stln }<div style=\"float:#{ algn }\">#{ out }</div>"
    end
    else
    out = stln + out
    end

    out
    end
    end

    虽然我不懂 Ruby ,不过看上去,这一行就是关键:

    atts = " src=\"#{ htmlesc url.dup }\"#{ atts }"

    看起来,生成<img>的“ src ”内容的,就是这一句,而这个 htmlesc 显然是一个函数,用于处理 URL.DUP 这个变量(这个我并不知道是什么,看字面意思似乎是将 URL 变量复制了一份?)

    于是就有了我上面的问题,我找到了最初对 htmlesc 这个函数的定义,希望通过修改它来达到我的目的。

    但奇怪的是,修改后,并没有如我想象的写回

    <img src="/attachments/download/455/">

    写回的是

    <img src="">

    所以我猜测,也许后面对输出的字符串还是做了什么修改,高度怀疑这几句:

    out = ''
    out << "<a#{ shelve( " href=\"#{ href }\"" ) }>" if href
    out << "<img#{ shelve( atts ) } />"
    out << "</a>#{ href_a1 }#{ href_a2 }" if href

    但是这个语法我就看不太懂了…………现在就卡在这里了………………
    zhs227
        16
    zhs227  
       2016-12-08 23:12:49 +08:00
    把 shelve 贴出来看看
    doun
        17
    doun  
       2016-12-08 23:32:41 +08:00 via Android
    我们也用 redmine ,没有遇到楼主说的问题啊!干嘛要用自己没什么概念的语言做的工具
    doun
        18
    doun  
       2016-12-08 23:36:08 +08:00 via Android
    htmlesc 是做类似 html safe 的动作,肯定很多调用的,不要改这个函数,有问题的话,直接加在这个地方好点
    wadezhao
        19
    wadezhao  
    OP
       2016-12-08 23:36:50 +08:00
    奇怪,函数最后一行的
    str
    我改成
    File.dirname('/attachments/download/455/02%E5%AE.jpg')
    可以正常输出 /attachments/download/455

    但是如果改成
    File.dirname(str)
    输出就成空字符串了,百思不得其解………………
    wadezhao
        20
    wadezhao  
    OP
       2016-12-08 23:41:12 +08:00
    @zhs227 我直接把 shelve 删掉了,这一行改成
    out << "<img#{ atts } />"
    输出没区别。而且看 19 楼我的新发现,应该还是这个 htmlesc 函数的问题


    @doun 是的,实际我是又做了一个 htmlesc_img 函数,只在这个地方用 htmlesc_img 函数。上面一直没说,只是方便讨论。
    redmine 在 Linux 下没问题,我在 Windows 上用 Bitnami 现成的安装包,根本不需要懂 Ruby ,很容易就部署,但就是有这个中文文件名的问题,我看网上很多人说,而且最新版的 Redmine 一样有这个问题,应该是 Ruby 或者 Windows 的问题。
    我用的是工具,是 Redmine ,不是 Ruby ,如果没这个 Bug , Redmine 是很好的一个工具。
    doun
        21
    doun  
       2016-12-08 23:49:05 +08:00 via Android
    贴一下你的函数?
    zhs227
        22
    zhs227  
       2016-12-08 23:50:24 +08:00
    你在不同的地方加一点输出,分段查看一下 url 的值。
    lightening
        23
    lightening  
       2016-12-08 23:51:34 +08:00
    这个 htmlesc 还用来出来 title ,见 `htmlesc title`。而且是直接改输入的,不依赖返回值。建议你还是不用动这个方法了。

    `atts = " src=\"#{ htmlesc url.dup }\"#{ atts }"`
    改成
    `atts = " src=\"#{ File.dirname(htmlesc(url.dup)) }\"#{ atts }"`
    liuhaotian
        24
    liuhaotian  
       2016-12-09 08:15:42 +08:00 via iPhone
    我觉得这个有点像是被 URLENCODE 了
    是不是那个 method 出了问题
    wadezhao
        25
    wadezhao  
    OP
       2016-12-09 11:16:03 +08:00
    @lightening 这个方法我试过了,返回的是空(或者是'./'),很奇怪吧
    wadezhao
        26
    wadezhao  
    OP
       2016-12-09 11:52:48 +08:00
    @doun
    @zhs227
    @lightening
    @liuhaotian

    现在最奇怪的,是这样的。首先,我又做了一个函数:
    def htmlesc_img( str, mode=:Quotes )
    if str
    str.gsub!( '&', '&amp;' )
    str.gsub!( '"', '&quot;' ) if mode != :NoQuotes
    str.gsub!( "'", '&#039;' ) if mode == :Quotes
    str.gsub!( '<', '&lt;')
    str.gsub!( '>', '&gt;')
    end
    str #这个地方我叫 [A 行]
    end

    然后把程序中这一句:
    atts = " src=\"#{ htmlesc url.dup }\"#{ atts }"
    改成
    atts = " src=\"#{ htmlesc_img url.dup }\"#{ atts }" #这一行我叫 [B 行]


    现在最诡异的情况在于:
    1 ,如果 B 行我不改动,或者说 htmlesc_img 的代码和 htmlesc 完全相同,或者干脆把 htmlesc_img 这个处理函数去掉,则会返回
    /attachments/download/455/02%E5%AE.jpg
    说明: url.dup 这个变量是有值的,值是待处理的正常值

    2 ,如果我把 A 行改为: File.dirname('/attachments/download/455/02%E5%AE.jpg'),可以正常输出
    /attachments/download/455
    这说明: atts 这个变量后续并没有被再处理,并且 File.dirname 这个函数执行的结果也是正常的

    3 , A 行如果改成
    v_temp = ''
    v_temp = v_temp+ File.dirname(str)
    或者
    v_temp = File.dirname(str)
    或者
    File.dirname(str)
    则返回的字符串是
    . (就是一个点儿)

    A 行如果改成
    str.split("/")[0..-2].join("/")
    则干脆返回一共空字符串

    也就是说,无论我怎么改,也没办法在 htmlesc_img 这个函数内,把 str 这个变量处理,让这个函数返回正确的内容,这太诡异了…………
    zhs227
        27
    zhs227  
       2016-12-09 12:25:09 +08:00   ❤️ 1
    直接用 log 吧,观察输出可能不靠谱。我测试过你这个函数一定是没有任何问题的

    irb(main):001:0> def htmlesc_img( str, mode=:Quotes )
    irb(main):002:1> if str
    irb(main):003:2> str.gsub!( '&', '&amp;' )
    irb(main):004:2> str.gsub!( '"', '&quot;' ) if mode != :NoQuotes
    irb(main):005:2> str.gsub!( "'", '&#039;' ) if mode == :Quotes
    irb(main):006:2> str.gsub!( '<', '&lt;')
    irb(main):007:2> str.gsub!( '>', '&gt;')
    irb(main):008:2> end
    irb(main):009:1> File.dirname(str)
    irb(main):010:1> end
    => :htmlesc_img
    irb(main):011:0> htmlesc_img '/attachments/download/455/02%E5%AE.jpg'
    => "/attachments/download/455"

    用日志或写文件方式,逐行记录,不可能这么诡异的
    wadezhao
        28
    wadezhao  
    OP
       2016-12-09 12:35:10 +08:00
    @zhs227 我怀疑是正斜杠和反斜杠的问题,很可能传进去的值是这样的?

    \attachments\download\455\02%E5%AE.jpg'
    wadezhao
        29
    wadezhao  
    OP
       2016-12-09 14:55:38 +08:00
    我找到原因了,写回页面的代码应该在别的地方还有处理,一言难尽,但我知道大概问题在哪里了,也知道各位告诉我的 File.dirname 这个函数是可用的。

    多谢各位,我继续解决问题了。 :)
    wadezhao
        30
    wadezhao  
    OP
       2016-12-09 15:44:52 +08:00
    解决了,原来 url 这个变量的值,就是'02%E5%AE.jpg',把前面的‘\attachments\download\455\’加上去,另有其他地方处理。

    在 application_helper.rb 里有一个函数: parse_inline_attachments ,是在这里解析最终输出的字符串,其中解析图片 URL 的一行是这样的:
    "src=\"#{image_url}\"#{alt}"

    如楼上各位指点,这一行改成
    "src=\"#{File.dirname(image_url)}\"#{alt}"

    就达到我的目的了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2759 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 00:24 · PVG 08:24 · LAX 17:24 · JFK 20:24
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.