python字符串用android,用Python解决Android布局中的字符串硬编码问题

Android布局中的硬编码

什么是Android布局中的硬编码

Android里的硬编码指在布局里直接填写值(如尺寸、颜色、字符等),而非对相关资源的引用。这里以android:text为例:

硬编码:

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="你好,我是硬编码"

android:textSize="@dimen/li_16sp_size"/>

软编码:

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@stirng/hard_code"

android:textSize="@dimen/li_16sp_size"/>

“你好,我是硬编码”在字符串资源里是这样的:

你好,我是硬编码

硬编码的优缺点

在Android布局中硬编码有什么优缺点呢,在我看来除了方便外,并没有别的优点,然而这个“优点”会为后面的维护扩展带来困难,所以也算不得什么优点,大致可认为这是Android开发中的一个坏习惯。这个坏习惯我们尽量要改掉,因为:

硬编码不利于复用

硬编码不利于维护

硬编码性能低于软编码

问题的出现

由于大多数场景下项目并没有涉及国际化,加上自己的一些不良习惯,经常在Android布局文件中进行硬编码。这通常不会出什么大问题,然而最近把项目转到Windows环境下开发,居然跑不起来了。报了这样的错误:

错误: Exception while handling step android.databinding.annotationprocessor.ProcessExpressions@572da56d javax.xml.bind.UnmarshalException

- with linked exception:

[org.apache.xerces.impl.io.MalformedByteSequenceException: Invalid byte 2 of 2-byte UTF-8 sequence.]

······

经查发现,这是因为在Windows环境下,布局中databinding相关的中文字符非UTF-8所致,也就是说,这是中文硬编码导致的问题。用Lint分析一下发现硬编码的地方有279个,叉,手动改的话还不改死人?而且手动,这违背程序员懒的美德。怎么办呢?刚好前段时间看了一下Python,那就用Python解决这个问题吧!

利用Python解决字符串硬编码问题

我们要做的事情,就是查找出布局文件里所有的中文字符串,并为其生成一个符合Android字符串资源命名规范的名字,构造字符串资源,然后将布局里所有的字符串替换为字符串资源的引用如@stirng/hard_code。如下:android:text="你好,我是硬编码"—>你好,我是硬编码—>android:text="@stirng/hard_code"。有思路之后,就可以动手了。

首先把项目res/layout文件夹复制出来,然后:

查找所有的硬编码字符串

Android布局文件中,可能硬编码的属性有android:text、android:hint、tools:text、尺寸相关的android:textSize、android:layout_width 、android:layout_height等这里我仅关注android:text、android:hint、tools:text即可。

#属性

#需将`android:`、`tools`替换为原命名空间

attrs = (

"{http://schemas.android.com/apk/res/android}text",

"{http://schemas.android.com/apk/res/android}hint",

"{http://schemas.android.com/tools}text",

)

1. 获取布局文件

def get_layout_files(path):

'''

获取所有的布局文件

:param path: 布局文件路径

:return:

'''

res = []

files = os.listdir(path)

for file in files:

res.append(path + "/" + file)

return res

2. 解析布局文件,这里我们用lxml的ElementTree来解析,所以我们需要引入:

try:

import xml.etree.cElementTree as ET

except ImportError:

import xml.etree.ElementTree as ET

a. 根文件获取ElementTree的根节点

def get_file_element_tree(file):

'''

更具文件名(路径)返回ElementTree根节点

:param file:

:return:

'''

tree = ET.ElementTree(file=file)

return tree.getroot()

b. 获取硬编码的属性值

def find_hard_code_attribute_value(tree_root, attrs):

'''

获取属性值

:param tree_root: ElementTree树根

:param attr: 要获取值的属性

:return: set() 返回值, 用集合保存,可以去掉重复的元素

'''

res = set()

for attr in attrs:

root_hard_code = tree_root.get(attr) # 获取根节点的硬编码

if root_hard_code is not None and len(root_hard_code) and str(root_hard_code).find("@string/") == -1:

# 如果属性值不会空且不是软编码()则就是我们要找的硬编码字符串

res.add(root_hard_code)

children = tree_root.findall(".//*[@" + attr + "]")

for child in children:

hard_code = child.get(attr) # 获取属性值

if hard_code is not None and len(hard_code) and str(hard_code).find("@string/") == -1:

# 如果属性值不会空且不是软编码()则就是我们要找的硬编码字符串

res.add(hard_code)

return res

生成strings.xml文件

1. 根据硬编码的字符串,生成对应的符合Android字符串资源命名规范的名称,用字典保存,字典key为硬编码字符串,value为对应的名称。

def generate_name_of_hard_code_string(hard_codes):

'''

根据硬编码字符串生成符合规范的名字,这里我们根据这样的规则生成名字:

a、英文字符串,则用其本省(出去空格、标点等)

b、中文字符串,则为其单字节拼音用"_"连接,如"硬编码"对应的名称为"yin_bian_ma",

这里的拼音转换我们通过pypinyin库来实现,如果涉及到分词,还需要安装jieba

:param hard_codes:

:return: 返回类型为字典,字典的键为硬编码的值,值则为根据硬编码生成的符合strings资源文件命名规范的字符串

'''

res = dict()

for hard_code in hard_codes:

hc = re.sub("""[\s+\.\!\/_,\{\}:$%^*()?+\"\']+|[+——+!:,\\\ 。?、~@#¥%……&*()]+""", "", hard_code) #去除特殊字符

py = ''

if hc is None or len(hc) == 0: #如果去除字符后为,则硬编码为特殊字符,这是我们就要随机命名

py = generate_random_string(15)

else:

py = lazy_pinyin(hc)

py = '_'.join(py)[0:25].strip() #限制长度,去除空格

try:

res[str(hard_code)] = py

except Exception as e:

print(e)

pass

return res

2.根据上一步生成的字典,构造strings.xml文件

def generate_strings_xml(file, dict):

'''

根据字典生成strings.xml文件

:param file: 文件路径

:param dict: 硬编码字符串和其名称构成的字典

:return:

'''

f = open(file,"w")

strings = []

strings.append('\n')

for (k, v) in dict.items():

temp = '\t' + k + '\n'

strings.append(temp)

strings.append("")

try:

f.writelines(strings)

f.close()

print("strings.xml文件生成成功")

except Exception as e:

print(e)

print("strings.xml文件生成失败")

pass

检查生成的strings.xml文件,手动进行命名优化。

替换硬编码字符串

1. 读取strings.xml中的字符串资源,构造字典。

def get_string_and_name_from_stringXML(file):

'''

读取strings.xml中的字符串资源,用字典保存

:param file:

:return:

'''

res = {}

root = get_file_element_tree(file)

strings = root.findall(".//string")

for str in strings:

res[str.text] = str.get("name")

return res

2.替换布局文件中的硬编码

def replace_hard_code(src_file, des_file, dicts):

'''

用字符串引用替换所有的字符

:param src_file: 带替换的布局文件

:param des_file: 替换后的文件

:param dict: 硬编码字典

:return:

'''

lines = open(src_file).readlines()

new_lines = []

for line in lines:

for (k, v) in dicts.items():

line = line.replace('="' + k +'"', '="' + "@string/" + v + '"')

if len(line.strip()) > 0:

new_lines.append(line)

with open(des_file, "w") as d_f:

d_f.writelines(new_lines)

最后

将生成的strings.xml文件内容最佳到项目字符串资源文件中。

再将生成的布局文件覆盖到项目res/layout目录下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值