一个英语编辑工作时要写哪些代码?
一个英语编辑工作时要写哪些代码?
缘起
最近前司(对,就是勇闯CYA系列里的前司)最近把我招回去做日语编辑的外包了。酬劳还不错,可以远程,时间很自由,按交付结果结算,算上我旅游副业和平时上课的课时费,每个月收入颇丰,颇有一种八方来财的感觉。
我之前负责的是英语的内容制作,日语虽是我二外,真实实力大概在N2.5左右,但是远远没到能够以一个绝对高于实习生的能力做审校工作,但是我可以无痛接手,用过往的经验和流程去确认编辑写给我的东西哪里可能有问题。在工作经验和计算机技术的降维打击下,项目工作效率直接起飞,并且因为出品比较稳定,合作也和我签到了2025年底。
最近一些人工做不来、必须得用脚本处理的工作多了起来,那技术不屑做、无法排期做的工作就由我这个脚本侠负责了,每个脚本还能在原先的基础上额外有些收入,岂不快哉,很开心我也是能够靠写代码赚钱的人了。
脚本合集
1. bold_lemma.py
字面意思,加粗单词。
假如要学习的单词是liben,例句是Ich Iiebe dich.(德语:我爱你。),在正确选择选项之后的单词信息页,liebe这个词就会被加粗,提示用户在这句话里,这个词是我们的目标词。
英语的加粗是前端做的,因为英语现成的词性还原工具很多、也很成熟,作为背英语起家的APP自然这方面实现得很好,但是换到西语、法语、德语、俄语、日语等小语种,这个加粗究竟怎么做,那就需要教研老师做研究,并提供方案了。
显而易见地,最简单的方案就是让做内容的人自己加粗,在需要加粗的单词前后加上井号,前端再解析成粗体就行了。但是人工一个个在目标词前后打上井号不仅慢,而且非常容易出错,肯定是需要机器做的,最终这个任务就交给了我。
我使用的方案也很简单啊,spaCy针对各个语种都有一个很完整的词形变化表,我只需要用它的nlp函数将句子token化,每个单词还原成原型,然后一个个对比,如果值是一样的就可以确定是目标词,然后加上井号输出即可。
def process_sent(nlp, word, sent):  
    tokens = nlp(sent)  
    new_sent = []  
  
    for token in tokens:  
        if token.lemma_ == word:  
            new_sent.append(f"#{token.text}#")  
        else:  
            new_sent.append(token.text)  
  
    highlighted_sentence = clean_spacing(' '.join(new_sent))  
    return highlighted_sentence
西语、德语、法语的模型用的都是dep_news_trf,俄语用的是core_news_lg,单纯因为它们模型体积最大,使用之后99.99%的单词都能正常加粗,完美满足下游其他语种编辑老师的需求。
当然,写完这个核心逻辑之后,还得处理一些擦屁股的需求,比如上面的clean_spacing()就是为了处理空格、标点等各种不规范使用的情况,包括把一些无法正确识别的大写俄语单词还原成小写,以及跳过动词不处理(这个由前端负责),输出成xlsx格式交付等。最后再写上try except处理意外情况,总共82行代码结束战斗。
比较值得一提的是,韩语的加粗100%是用GPT写的手写规则,因为模型不好用,只有60%左右的成功率,最后我和负责韩语的教研老师反复研究了好几轮,综合我的语言学知识,由我来和ChatGPT描述问题并获取代码测试(韩语老师对此毫不知情),最后写出了一个我自己都无法维护的脚本,以90%的成功率通过了验收。
韩语的部分大概分成几层逻辑:
首先,对于单词后缀稳定的名词、副词,用正则表达式匹配目标词开头,后面跟0-4韩语音节字符的词,这个几乎是100%捕获。
pattern = re.compile("^" + re.escape(word) + r"(?P<suffix>[가-힣]{0,4})$")
其次,对于变形极其不稳定的动词来说,先把大部分하다结尾的词搞定了,这是一个能够把外来语名词变成动词的词缀,例如공부是学习(名词),공부하다就变成动词了,韩语中有非常多的汉语借入词汇,这条规则能捕获一大半动词。
同理,还有很多动词是以이다结尾的情况(也就是大家常说的「思密达」),也应该单独安排一条规则。
所有其他情况我就让GPT分成了几轮,不断地去把例外规则囊括进去,一个是时态变化,一个是乱七八糟无法总结的特殊词尾。是否齐全我无法求证,反正跑起来甲方满意就行了,反正这个是我完全不可能写得出来的东西。
tense = r'''  
    (?:었|았|였|렀|졌|낫|더|더러|길|시|면|려고|인|적인|이|해|했|겼|켰|웠|쉈|줬|됐|됬|쁜|\s)|  
'''.strip()
endings = r'''  
    (?:다|고|서|는|을|지|라|니|습니까|니다|데|든지|운|한|할|려|여|면|며|되|되는|로|도록|옵|더러|하는|같은|랑|기|게|하|하였|했|합니다)  
'''.strip()
就这样,每个语种单独结算一次酬劳,靠这个需求还是赚了不少零花钱的嘿嘿。
不过之后每次编辑做完内容都要过来找我加粗句子,毕竟他们都不会代码。不过无所谓了,反正处理一次也花不到几秒钟,无非就是下载对面给过来的xlsx文件,我再改个路径名而已,核心生产资料掌握在我手上就行。
2. check_pic_size.py
APP对于图片的尺寸、比例和大小是有要求的。
通常在实际生产工作中,我们在给小语种单词配图的时候通常会从这几个渠道入手:
- 原数据库内的英语词(如日语“困难”難しい,我们会优先找英语difficult的可用图片)
 - 合作的图片素材库
 - AI作图
 
1的渠道占了将近60%的量,毕竟这么多年下来,英语的内容积累了非常多,复用起来非常方便,基本上大部分日常你能想到的单词都已经有比较好的图了。但也正是因为年代过于久远,很多以前的图片大小可能仅有330x220左右的像素,远远没办法满足现在电子设备的分辨率。编辑们在挑选图片的时候,往往会无意识地选到一些应该被淘汰掉的糊图。
由于在上传数据和制作图片时我们打交道的都是内部cdn链接,直接判断图片尺寸是否合格人工一个个点击下载查看属性非常之麻烦,不如索性做完之后再回过头来筛查图片尺寸,如果有需要改的再重新制作,这样工作效率会高一些。
图片尺寸筛选的脚本也不难,只需要两个函数,一个负责把图片从公司cdn批量下载下来,一个负责检查尺寸就行。前者用requests对着cdn链接直接下载就行,后者我用的是PIL模块,非常简单。
每一本新词书制作完成之后,我都会走一遍这个流程。
from PIL import Image  
import os  
  
image_folder = ""  
  
for filename in os.listdir(image_folder):  
    file_path = os.path.join(image_folder, filename)  
  
    try:  
        with Image.open(file_path) as img:  
            width, height = img.size  
            aspect_ratio = round(width / height, 2)  
  
            if not ((width == 800 and height == 600) or aspect_ratio == 1.33):  
                print(f"Mismatch: {filename} ({width} x {height})")  
  
    except Exception as e:  
        print(f"Unreadable or invalid file: {filename} ({e})")
3. 释义树系列
释义树系列的需求算是我回归外包之后做的技术力的巅峰,我和ChatGPT配合的那叫一个天衣无缝。虽然有的部分让我自己写,我多花点时间琢磨也能写得出来,但是能够精准拆分问题、描述问题,让GPT一次就生成一个可用函数的快感真的无与伦比。
总之需求就是需要从一个包含大部分常见单词的字典文件里分离出每个单词的词根词缀,它的编码格式是这样的:假设单词是internationalisation,词根会用括号标记,前缀用<<,后缀用>>,所以这个词在字典里的标记长这样——<inter<(nation)>al>>is>>ation>,可以看到这里有1个前缀、1个词根、3个后缀,我的第一个任务就是将其分离开,并按照前缀1234、词根123、后缀1234排列好。
可能在不会代码的人眼里,这个工作可能很难,但是其实正则表达式就能解决了,此处放上GPT的含注释纯享代码,一个字符都没带改的。后面转化成json和xlsx的代码就不展示了。
def process_morphemes(morphemes_str):  
    morphemes = []  
  
    # Patterns to extract prefixes, roots, and suffixes  
    prefix_pattern = r'<([^<>]+)<'  # For prefixes  
    root_pattern = r'\(([^()]+)\)'    # For roots  
    suffix_pattern = r'>([^<>]+)>'  # For suffixes  
  
    # Extract prefixes    prefixes = re.findall(prefix_pattern, morphemes_str)  
    for i, prefix in enumerate(prefixes):  
        morphemes.append({  
            f"Prefix{i+1}": prefix,...剩余内容已隐藏