平方X

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 4048|回复: 0

[2501]OmegaT 校验机器翻译的结果

[复制链接]

414

主题

709

帖子

3656

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3656
QQ
发表于 2018-1-10 15:42:45 | 显示全部楼层 |阅读模式
[md]
# 0x01 java 中改写 python 中的正则
python 中的
```
        chinese_pattern = r'([\u4e00-\u9fa5])'
        need_space_pattern = r'([a-zA-Z]|{\d}+|\'.+?\'|\".+?\")'
        cn = re.sub(chinese_pattern + need_space_pattern, r'\1 \2', cn)
        cn = re.sub(need_space_pattern + chinese_pattern, r'\1 \2', cn)
```
变为了
```
    public static String formatTranslation(String en, String cn) {
        // \u 需要转义
        String chinesePattern = "([\\u4e00-\\u9fa5])";
        // { 需要转义,但 } 不需要
        String needSpacePattern = "([a-zA-Z]|\\{\\d}|'.+?'|\".+?\")";
        // 要使用 $ 不能使用 \
        cn = cn.replaceAll(chinesePattern + needSpacePattern, "$1 $2");
        cn = cn.replaceAll(needSpacePattern + chinesePattern, "$1 $2");
        return cn;
    }
```
> `Note that backslashes (\) and dollar signs ($) in the replacement string may cause the results to be different than if it were being treated as a literal replacement string. Dollar signs may be treated as references to captured subsequences as described above, and backslashes are used to escape literal characters in the replacement string.`


# 0x02 java 中运行 python--jython
[github/jython](https://github.com/jythontools/jython)
```
        PythonInterpreter interpreter = new PythonInterpreter();
        interpreter.execfile("lib/translation_inspection.py");
        PyFunction function = interpreter.get("inspect_space", PyFunction.class);
        PyObject result = function.__call__(new PyString(en), new PyString(cn));
```

## 2.1 声明编码
> SyntaxError: Non-ASCII character in file 'lib/translation_inspection.py', but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

## 2.2 删除不需要的 import
ImportError: No module named

## 2.3 删除不能调用的方法
main 方法
StandardTranslation.inspect_translation

## 2.4 java.lang.IllegalArgumentException: Cannot create PyString with non-byte value
一开始用的
```
        PyFunction function = interpreter.get("inspect_space", PyFunction.class);
        PyObject result = function.__call__(new PyString(en), new PyString(cn));
```
然后报错
java.lang.IllegalArgumentException: Cannot create PyString with non-byte value

又更新了 2.7.1 (不过后来换为 2.7.0 还是不行),结果 function 找不到了(原本就应该找不到才对)  
于是改为
```
        PyClass pyClass = interpreter.get("TranslationInspection", PyClass.class);
        PyObject result = pyClass.invoke("inspect_space", new PyString(en), new PyString(cn));
```
还是报 java.lang.IllegalArgumentException: Cannot create PyString with non-byte value

又去翻了一下 issues ,
[90#](https://github.com/jythontools/jython/issues/90)
好像有一些修复,但是换为 Py.newStringOrUnicode() 就可以了。

## 2.5 正则替换方法不正确
之前的经验,应该是后向引用的 \ 不正确,试了一下,python 中也可以使用 $ 后向引用。  
于是用将 \\(?=\d) 替换为 \$  
但是发现无效,已经进行转义了。好像是对中文的解析不正确,也可能是位置计算有错。  
你好java语言 被处理为   
你好j av a语言  
测试发现匹配出的结果是 ja ,而正确的应该是 好j

再后来发现,
[渐行渐远silence《Python正则匹配中文与编码总结》](http://blog.csdn.net/silence2015/article/details/60321873)
>关于Python正则表达式匹配中文,其实只要同意编码就行,我电脑用的py2.7,所以字符串前加u,在正则表达式前也加u即可。


>Jython follows closely the Python language and its reference implementation CPython, as created by Guido van Rossum. Jython 2.7 corresponds to CPython 2.7.

于下修改为 u,测试成功。
```
替换
r(?=\'.+?\[\\u4e00-\\u9fa5])

u
```

## 2.6 单例
测时发现 new 是一个耗时操作,约需要 2 点几秒。于是用单例保存了 function
```
PythonInterpreter interpreter = new PythonInterpreter();
```

测试发现,第一次两个插件都调用了该类,初始化只调用一次,但两次调用耗时都挺长。  
原因应该是等待单例构造完毕。

然后第二次调用就很快了。



# 0x03 资源的加载
要使用 .py 文件,和之前使用 .js 一样,要考虑如何加载的问题。  
放到目录中,或者压缩到 jar 包中,之前放到 jar 包中总是无法加载,这一次又学习了一下。
## 3.1 文件的引用
```
//路径,测试时是模块的根目录,运行项目时是项目的根目录
interpreter.execfile("lib/translation_inspection.py");
```
所以要使用文件的话,测试模块要在模块中新建目录存放,在运行项目时也要在项目中存放。

## 3.2 stream
之前使用过,
```
InputStream inputStream = GoogleTk.class.getResourceAsStream("resource/google_tk.js");
InputStream inputStream = ClassLoader.getSystemResourceAsStream("resource/google_tk.js");
```
当时使用前者不可以,使用后者是可以的,但是后者生成 jar 包后就无法加载了。  
(后面会介绍原因是 resolveName )  

### java.lang.ClassLoader#getSystemResourceAsStream
调用顺序为
```
java.lang.ClassLoader#getSystemResourceAsStream
java.lang.ClassLoader#getSystemResource
java.lang.ClassLoader#getResource
java.lang.ClassLoader#findResource
java.net.URLClassLoader#findResource
接下来调用
        URL url = AccessController.doPrivileged(
            new PrivilegedAction<URL>() {
                public URL run() {
                    return ucp.findResource(name, true);
                }
            }, acc);
这是是 native 方法,但是多次调用了下面的方法,
sun.misc.URLClassPath#findResource
它持有 loaders 字段
sun.misc.URLClassPath#loaders 中有多个 loader
```
发现 loaders 中只有 resources 、 classes 目录,并没有插件的 jar 包。

### java.lang.Class#getResourceAsStream
java.lang.Class#getResourceAsStream
```
     public InputStream getResourceAsStream(String name) {
        //被修改了名字
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResourceAsStream(name);
        }
        return cl.getResourceAsStream(name);
    }
...
后面一样调用到
sun.misc.URLClassPath#findResource
```
但是此时比前面多了一个 URLClassPath
第一个包含 jdk/jre/lib/ext/ 中的一些 jar 包;  
第二个包含很多,应该是项目使用的, jdk 的,IDEA(用其运行)的 jar 包,以及输出 out/production/classes 和 resources  
第三个终于是 plugins 中的 jar 包了

发现是 java.lang.Class#resolveName 修改了名字,于是加上 / 就成功了。
```
    InputStream in = BaseTranslatorX.class.getResourceAsStream("/translation_inspection.py");
    private String resolveName(String name) {
        if (name == null) {
            return name;
        }
        if (!name.startsWith("/")) {
            Class<?> c = this;
            while (c.isArray()) {
                c = c.getComponentType();
            }
            String baseName = c.getName();
            int index = baseName.lastIndexOf('.');
            if (index != -1) {
                name = baseName.substring(0, index).replace('.', '/')
                    +"/"+name;
            }
        } else {
            name = name.substring(1);
        }
        return name;
    }
```

## test 和项目都能使用
运行项目可以从 jar 包中加载,可运行 test ,只有 out/production 和 out/test  
于是我就写了先看文件是否存在。
```

        //文件路径,不以 / 开头,测试时是模块的根目录,运行项目就是项目的根目录
        File file = new File("lib/translation_inspection.py");
        if (file.exists()) {
            try {
                interpreter.execfile(file.getAbsolutePath());
                System.out.println("load py from file");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            //以 / 开头,不会被处理,最后从 jar 中加载到资源
            InputStream in = BaseTranslatorX.class.getResourceAsStream("/lib/translation_inspection.py");
            if (in != null) {
                try {
                    interpreter.execfile(in);
                    System.out.println("load py from input stream");
                    in.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                System.out.println("py input stream is null");
            }
        }
```
但是 out/production 中应该有 resources 目录的呀。  
后来看了一下,这个 resources 目录对应 main/resources 与 main/java 同一级。  
于是放进去就好了。[/md]
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|手机版|Archiver|平方X ( 冀ICP备14018164号 )

GMT+8, 2024-11-21 20:56 , Processed in 0.091872 second(s), 21 queries .

技术支持:Powered by Discuz!X3.4  © 2001-2013 Comsenz Inc.

版权所有:Copyright © 2014-2018 平方X www.pingfangx.com All rights reserved.

快速回复 返回顶部 返回列表