这个问题我研究了两天无法解决,希望大家可以教我。
起因是使用 emms 可以正常显示,但是无法播放韩语、泰语文件名的歌曲。后来找到原因是 start-process 函数无法正确传递 utf-8 编码的参数,与 emms 无关。
函数描述:
(start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)
我在纯净的 emacs 下这样测试的:
(start-process “test1” nil “notepad” “시린”)
notepad 得到的参数只能是 “鞁滊Π” 这样的乱码,我尝试过修改了很多关于编码的选项都无济于事。
比如:
(set-language-environment “utf-8”)
(setq default-process-coding-system '(utf-8 . utf-8)) ;; 如果修改为 cp936 那么除英中日文正常,其他都会变成空白,修改为 utf-8 则除英文外全部乱码。
(w32-set-console-codepage '65001) ;;怎么修改都无变化
(w32-set-console-output-codepage '65001) ;;怎么修改都无变化
平台:win8.1 64/ win7 64
编译版本:官方编译版本 25 / 26 / 27 纯净无添加
cp936 不支持韩国字。
可能要改系统的编码,不是很了解这块(chcp
只影响命令行?)。
有没有人试过 Windows 10?
终于发现有同僚也发现这个问题了
起初我因为觉得这个问题太小众了,懒得提问了,既然有同僚了那就水一下:
看楼主也是在win下得到这个问题的吧,发一下我的平台信息:
- Operation-system: win10 1709
- emacs-version: GNU Emacs 26.1 (build 1, x86_64-w64-mingw32) of 2018-04-10
我的问题:
一开始我在windnows中使用emacs想要调用外部程序, 我使用了函数 w32-shell-execute
, 这个函数有一个特点:
它是使用内部钩子调用win的api来联动win下与该文件类型关联的程序:
比如这个钩子: open
如果要实现外部打开一个文件,可以这样:
(w32-shell-execute "open" "file-name")
在函数参数描述中,形式是这样的:
(w32-shell-execute OPERATION DOCUMENT &optional PARAMETERS SHOW-FLAG)
这让我很开心但是有一个不满足的地方,就是,无法调用指定程序打开某一个文件。
于是我再仔细看了一下这个函数的描述文档,发现它是可以使用参数的,也就是这个optional参数选项中的第一个位,并且我发现"DOCUMENT"这个参数是既可以是文件也可以是可执行程序的,那么联合额外参数,就可以使用指定程序打开一个文件了:
(w32-shell-execute "open" "D:/PortableApps/mpc/bin/mpc-hc.exe" "\"E:/episode/Downton Abbey/1.mp4\"")
可是我发现这个参数只能使用本地locale和latin两种编码,不能使用其他的诸如韩语,法语等,如果把一个韩语命名的文本文件传入nodepad++的话,文件名是乱码的,然后外部程序提示,无法找到文件!
于是乎我选择使用 universal-coding-system-argument
来临时调用一下韩文编码,依然乱码,。。。。。。。。。卒
求救中。。。。。
1 个赞
假定你升级了Windows10最新更新
- 打开系统Region & Language 设置
- 往下滚动,选择Related settings中的Administrative language settings
- 选择Change system local…
- 勾选 Beta: Use Unicode UTF-8 for worldwide language support
好了,进入Emacs,执行(setq w32-system-coding-system 'utf-8)
(w32-shell-execute “open” “notepad.exe” “中文文件名.txt”)应该正常了
2 个赞
我们遇到的有可能是一个问题。
我有个临时办法来解决,就是自己写个程序,处理 emacs 传递过来的参数。比如:
(start-process "test1" nil "program.exe" "utf-8 编码的参数")
program.exe
接到的参数是乱码,可以经过编码转换变得正常,然后 program.exe
再利用正常的参数调用其他程序。
program.exe 的 c# 代码简单例子:
string newArg = Encoding.UTF8.GetString(Encoding.Default.GetBytes(arg));
Process p = new Process();
p.StartInfo.FileName = "notepad++.exe";
p.StartInfo.Arguments = newArg;
p.Start();
这个方法我觉得是不会有用的,因为参数在传递给外部程序以前已经丢失了。
如果你观察Emacs源码w32fns.c的Fw32-shell-execute函数,你会看到参数是用locale-coding-system编码的(也就是w32-system-coding-system):
parameters = ENCODE_SYSTEM (parameters);
然后再用当前系统代码页转换到utf-16:
len = pMultiByteToWideChar (CP_ACP, multiByteToWideCharFlags,
SSDATA (parameters), -1, NULL, 0);
为了保留多国语言字符,必须确保每一步都保留了unicode。
(setq w32-system-coding-system 'utf-8) // 或者 (setq locale-coding-system 'utf-8)
保证了第一步能够在parameters里得到utf-8的字符串
把系统代码页设置成utf-8可以保证第二步从utf-8转换到utf-16
如果不改系统代码页,直接改Emacs源代码,用CP_UTF8估计也可以。
1 个赞
有意思的是w32-shell-execute的第二个参数document并不需要这么折腾,随便放任意语言的字符串都可以。因为源码里这个参数是用file-name-coding-system编码的,在windows上默认就是utf-8:
document = ENCODE_FILE (document);
这看来是要升级insider开发版的节奏哇,我是怕不稳定,再来win7是没有这个选项的。
公司电脑是win7, 看来只有按照你下面一条提示回复所说的改源代码了,但是这个patch会不会牵连其他内置组件?风险会不会很大?
二来,我现在的想法是,用elisp写一个小函数把文件名传入到一个temp文件,然后调用外部的一个C的几行代码的操作函数提取它,然后运行。 下午试一下。
win10不需要上insider channel,最新的公开版本已经有这个选项了(虽然上面标着beta)
谢谢提醒, 好久回顾此贴。现在在测试magit,之前由于magit在codepage为65001下无法工作,因此一直耽搁了。
正好搜start-process
的时候看到这个贴子,start-process
底层就是调用make-process
(defun start-process (name buffer program &rest program-args)
(unless (fboundp 'make-process)
(error "Emacs was compiled without subprocess support"))
(apply #'make-process
(append (list :name name :buffer buffer)
(if program
(list :command (cons program program-args))))))
而 make-process
是有 coding参数的