Python日常-正则表达式批量替换dimens.xml中的单位

事情起源

最近做的Android项目中出现了一个这样的需求:不同宽度的设备上,控件的尺寸按比例缩放。也就是说,假如在360dp宽的设计稿上,某个Button的宽度为120dp,那么到了480dp宽的设备上,这个Button的宽度应该拉成160dp。一开始我想到了几种思路:

  • 全部用layout_weight,但是这样太麻烦了
  • 百分比布局,还是一样,需要计算百分比,太麻烦
  • 鸿洋_推出的AutoLayout,但我一看Github上的issues,似乎很多坑的样子,不敢试
  • 布局里面的宽高全部写到dimens.xml中,然后为不同宽度的设备写多套dimens.xml,这样做比较麻烦,但现在看来是最有效的办法

也就是说,我会把一个Button的布局代码写成这样(所有长度单位全部写到dimens.xml里):

<Button
        android:layout_marginTop="@dimen/login_button_margin_top"
        android:id="@+id/id_button_login"
        android:layout_width="@dimen/large_button_width"
        android:layout_height="@dimen/standard_widget_height"
        android:layout_gravity="center"
        android:textSize="@dimen/sp15"
        android:text="登录"
        android:textColor="@color/white"
        android:gravity="center"
        />

然后在values/dimens.xml里面,定义这些单位:

<resources>

    <!-- Widget Width && Height -->
    <dimen name="toolbar_height">@dimen/standard_widget_height</dimen>
    <dimen name="large_button_width">270dp</dimen>
    <dimen name="standard_widget_height">42dp</dimen>

    <!--Margin && Padding-->
    <dimen name="login_button_margin_top">30dp</dimen>
   
</resources>

创建values-w480dp目录,在里面的dimens.xml定义(如果设计稿的屏幕宽度是360dp,那么这里乘以一个三分之四):

<resources>

    <!-- Widget Width && Height -->
    <dimen name="toolbar_height">@dimen/standard_widget_height</dimen>
    <dimen name="large_button_width">360dp</dimen>
    <dimen name="standard_widget_height">56dp</dimen>

    <!--Margin && Padding-->
    <dimen name="login_button_margin_top">40dp</dimen>
   
</resources>

但是随着项目布局文件的增多,dimens里面的标签数量也会水涨船高,到时候难道为每一个宽度的布局都去算一遍宽高吗?这显然太费人力了

思路

于是我就想写个脚本来自动化地做这件事,人生苦短,首选武器必然是Python。一下子思路就很简单:找出所有xxdp的文本,把数值解析出来,乘以一个倍数,再写回去

所以问题就变成了怎么把xxdp解析出来,一开始想到的是XML解析库,网上看了一下,想用xml.dom.minidom这个包,后来发现解析出来后不知道咋把数值写回去(肯定可以的,但我太懒了不想去看文档),所以干脆就用正则表达式了。我用这样一个表达式来把dimens.xml里面的单位给匹配出来:

> *(\w+)[sd]p *<

这里我假设单位都是整数,为了防止里面有空格加了个' *',这样(\w+)所匹配出来的就是dp或sp的数值了。写回去好办,把匹配出来的数值改一改再替换回去就是了。

代码

最后的代码长这样:

import re

def auto_transfrom_reg(res_path, new_res_path, t):
    value_file_360p_path = res_path + '//values//dimens.xml'
    new_value_file_path = res_path + new_res_path
    file_handler = open(value_file_360p_path)
    new_file_handler = open(new_value_file_path, 'w')
    line = file_handler.readline()
    while line:
        match_obj = re.search(r'> *(\w+)[sd]p *<', line)
        if match_obj:
            dp_str = match_obj.group(0)
            new_dp_str = ''
            if dp_str.find('d') >= 0:
                dp_value = int(dp_str[1:dp_str.find('d')])
                new_dp_value = dp_value * t
                new_dp_str = '>%.1fdp<' % new_dp_value
            else:
                dp_value = int(dp_str[1:dp_str.find('s')])
                new_dp_value = dp_value * t
                new_dp_str = '>%.1fsp<' % new_dp_value
                print new_dp_str
            new_line = re.sub(r'> *(\w+)[sd]p *<', new_dp_str, line)
            new_file_handler.write(new_line)
            print new_line
        else:
            new_file_handler.write(line)
        line = file_handler.readline()
    pass

if __name__ == '__main__':
    auto_transfrom_reg('E://XXX//YYYY//app//src//main//res',
                       '//values-w480dp//dimens.xml', 480.0/360)

效果自然是完美替换:

对比
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容