Форум: "Прочее";
Текущий архив: 2008.02.24;
Скачать: [xml.tar.bz2];
ВнизКак добиться, чтобы русский текст письма выглядел по-русски... Найти похожие ветки
← →
Игорь Шевченко © (2008-01-23 13:22) [0]Вне зависимости от почтового клиента, которым письмо читают.
Рассылаю я письма (нужда такая). Соответственно, сабж.
Письмо в результате выглядит следующим образом (часть заголовков посгрызена мышами):
From: Sender <sender@foo.bar>
To: recipient@foo.com
Subject: =?Windows-1251?Q?Subject?=
X-Mailer: XMailer v1.15
MIME-Version: 1.0
Content-Type: multipart/mixed;boundary="_NextPart_00009A28-00001D02-01C999C0-9345"
Content-Transfer-Encoding: 8bit
Date: 17 Jan 2008 17:49:11 +0300
Status:
--_NextPart_00009A28-00001D02-01C999C0-9345
Content-Type: text/html
Content-Transfer-Encoding: 7bit
<html>
<head>
<title></title>
<META http-equiv=Content-Type content="text/html; charset=windows-1251">
</head>
<body bgcolor="White" text="Black" link="#006699" vlink="#006699" alink="blue">
<p> </p>
<p>Ты сам несъедобный крысиный хвост foo.htm</p>
<BR>
</body>
</html>
--_NextPart_00009A28-00001D02-01C999C0-9345
Content-Type: application/octet-stream;name="foo.htm"
Content-Transfer-Encoding: base64
....
Разные почтовые клиенты видят текст внутри письма по-разному, большинство отображает русский текст "Ты сам несъедобный крысиный хвост", а часть отображает в перевернутой кодировке:
рШ ЯЮЛ МЕЯЗЕДНАМШИ ЙПШЯХМШИ УБНЯР
Куды бечь и что можно сделать, чтобы текст читался так, как задумано :)
Почтового клиента сменить не предлагать.
← →
ZoldBerger (2008-01-23 13:24) [1]Для начала, попробуй Методом таблицы модельных распределений определить кодировку
type
TCodePage = (cpWin1251, cp866, cpKOI8R);
PMap = ^TMap;
TMap = array[ #$80..#$FF] of Char;
function GetMap(CP: TCodePage): PMap;
{ должна возвращать указатель на таблицу перекодировки из CP в Windows1251
(nil для CP = cpWin1251) }
begin
GetMap := nil;
end;
function DetermineRussian(Buf: PChar; Count: Integer): TCodePage;
const
ModelBigrams: array[0..33, 0..33] of Byte = (
{АБВГДЕЖЗИЙКЛМHОПРСТУФХЦЧШЩЪЫЬЭЮЯ_?}
{А}(0, 20, 44, 12, 22, 23, 16, 60, 4, 9, 63, 93, 47, 110, 0, 16, 35, 61, 81,
1, 5, 13, 24, 17, 12, 4, 0, 0, 0, 0, 14, 31, 205, 1),
{Б}(19, 0, 0, 0, 4, 19, 0, 0, 8, 0, 2, 15, 1, 4, 41, 0, 15, 5, 0, 15, 0, 2,
1, 0, 0, 6, 16, 37, 0, 0, 0, 4, 3, 0),
{В}(97, 0, 1, 0, 2, 57, 0, 5, 40, 0, 4, 25, 2, 23, 78, 2, 8, 28, 4, 12, 0,
1, 0, 0, 8, 1, 0, 40, 1, 0, 0, 5, 106, 3),
{Г}(13, 0, 0, 0, 9, 5, 0, 0, 15, 0, 1, 17, 1, 2, 96, 0, 24, 0, 0, 7, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0),
{Д}(63, 0, 9, 1, 2, 71, 1, 0, 35, 0, 3, 16, 2, 22, 50, 2, 19, 9, 2, 25, 0,
2, 1, 0, 1, 0, 1, 9, 4, 0, 1, 5, 17, 4),
{Е}(4, 14, 15, 34, 56, 22, 13, 14, 2, 34, 39, 77, 73, 150, 6, 9, 101, 64,
81, 1, 0, 15, 5, 12, 10, 6, 0, 0, 0, 0, 3, 4, 235, 1),
{Ж}(13, 0, 0, 0, 12, 47, 0, 0, 16, 0, 1, 0, 0, 23, 0, 0, 0, 0, 0, 3, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2),
{З}(76, 2, 11, 3, 11, 4, 1, 0, 7, 0, 2, 4, 11, 24, 17, 0, 6, 1, 0, 8, 0, 0,
0, 0, 0, 0, 0, 16, 6, 0, 1, 4, 17, 0),
{И}(7, 9, 32, 5, 18, 60, 4, 42, 31, 27, 28, 46, 55, 49, 12, 7, 26, 60, 53,
0, 5, 25, 14, 28, 4, 1, 0, 0, 0, 0, 9, 56, 255, 0),
{Й}(0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 3, 0, 3, 0, 0, 0, 10, 3, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 122, 0),
{К}(92, 0, 3, 0, 0, 7, 2, 1, 39, 0, 0, 27, 0, 14, 110, 0, 18, 5, 35, 18, 0,
0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0),
{Л}(85, 1, 0, 2, 1, 70, 6, 0, 85, 0, 5, 3, 0, 9, 67, 1, 0, 9, 0, 15, 0, 0,
0, 2, 0, 0, 0, 9, 66, 0, 15, 43, 57, 4),
{М}(44, 0, 0, 0, 0, 65, 0, 0, 47, 0, 1, 1, 10, 15, 57, 7, 0, 2, 0, 24, 0, 0,
0, 0, 0, 0, 0, 28, 0, 0, 0, 8, 109, 3),
{}(139, 0, 0, 1, 11, 108, 0, 4, 152, 0, 7, 0, 1, 69, 161, 0, 0, 8, 25, 24,
5, 1, 5, 2, 0, 1, 0, 83, 10, 0, 1, 29, 38, 5),
{О}(0, 72, 139, 76, 74, 32, 32, 19, 12, 52, 21, 93, 68, 72, 7, 34, 93, 102,
98, 1, 2, 6, 6, 19, 15, 2, 0, 0, 0, 1, 4, 9, 252, 2),
{П}(17, 0, 0, 0, 0, 43, 0, 0, 14, 0, 1, 9, 0, 1, 125, 3, 120, 1, 2, 8, 0, 0,
0, 0, 0, 0, 0, 3, 6, 0, 0, 3, 2, 2),
{Р}(151, 1, 6, 4, 3, 103, 7, 0, 76, 0, 4, 0, 11, 10, 117, 1, 0, 5, 9, 39, 2,
5, 0, 1, 3, 0, 0, 24, 7, 0, 1, 10, 22, 5),
{С}(24, 1, 21, 0, 3, 39, 0, 0, 33, 0, 56, 41, 11, 15, 58, 30, 5, 30, 183,
16, 0, 4, 1, 4, 1, 0, 0, 8, 25, 0, 1, 50, 41, 2),
{Т}(83, 0, 43, 0, 3, 87, 0, 0, 71, 0, 9, 3, 2, 26, 180, 0, 55, 33, 1, 23, 1,
0, 1, 4, 0, 0, 0, 20, 78, 0, 0, 5, 82, 4),
{У}(3, 6, 7, 14, 19, 8, 13, 6, 0, 1, 13, 15, 10, 7, 0, 12, 17, 16, 19, 0, 1,
3, 0, 12, 5, 8, 0, 0, 0, 0, 22, 1, 65, 0),
{Ф}(4, 0, 0, 0, 0, 4, 0, 0, 11, 0, 0, 1, 0, 0, 9, 0, 3, 0, 0, 4, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 2, 0),
{Х}(9, 0, 2, 0, 0, 2, 0, 0, 5, 0, 0, 1, 0, 5, 26, 0, 4, 1, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 76, 0),
{Ц}(5, 0, 0, 0, 0, 16, 0, 0, 48, 0, 1, 0, 0, 0, 4, 0, 0, 0, 0, 3, 0, 0, 0,
0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0),
{Ч}(30, 0, 0, 0, 0, 52, 0, 0, 23, 0, 3, 1, 0, 14, 1, 0, 0, 0, 36, 5, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 2),
{Ш}(13, 0, 0, 0, 0, 28, 0, 0, 17, 0, 4, 4, 0, 4, 3, 0, 0, 0, 1, 3, 0, 0, 0,
0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 1),
{Щ}(6, 0, 0, 0, 0, 23, 0, 0, 16, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1),
{Ъ}(0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 0, 0),
{Ы}(0, 5, 14, 1, 3, 28, 0, 2, 0, 22, 6, 19, 21, 2, 0, 5, 4, 7, 10, 0, 0, 37,
0, 3, 4, 0, 0, 0, 0, 0, 0, 1, 84, 0),
{Ь}(0, 1, 0, 0, 0, 9, 0, 10, 1, 0, 13, 0, 2, 26, 0, 0, 0, 10, 3, 0, 0, 0, 1,
0, 6, 0, 0, 0, 0, 0, 6, 4, 117, 0),
{Э}(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 31, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
{Ю}(0, 5, 0, 0, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 15, 0, 0, 0, 1, 4,
1, 15, 0, 0, 0, 0, 0, 0, 38, 0),
{Я}(0, 0, 9, 2, 7, 10, 3, 19, 0, 0, 1, 6, 7, 8, 0, 0, 2, 6, 19, 0, 0, 3, 5,
1, 0, 3, 0, 0, 0, 0, 5, 2, 177, 0),
{_}(42, 80, 193, 43, 109, 41, 18, 53, 159, 0, 144, 27, 83, 176, 187, 229,
70, 231, 99, 47, 15, 13, 6, 58, 7, 0, 0, 0, 0, 38, 0, 22, 0, 2),
{?}(0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 2, 4, 4, 8, 0, 0, 5, 3, 4, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
{ " рейтинг" буквы ? условно принимается равным 1/20 от " рейтинга" буквы E,
если сочетание с участием ? корректно, иначе - 0 }
type
TVariation = array[0..33, 0..33] of Integer;
var
I, J, iC, iPredC, Max: Integer;
C: Char;
CP: TCodePage;
D, MinD, Factor: Double;
AMap: PMap;
PV: ^TVariation;
Vars: array[TCodePage] of TVariation;
begin
DetermineRussian := cpWin1251; { по yмолчанию }
{ вычисление распределений биграмм }
FillChar(Vars, SizeOf(Vars), 0);
for CP := Low(Vars) to High(Vars) do
begin
AMap := GetMap(CP);
PV := @Vars[CP];
iPredC := 32;
for I := 0 to Count - 1 do
begin
C := Buf[I];
iC := 32;
if C > = #128 then
begin
if AMap < > nil then
C := AMap^[C];
if not (C in ["?", "?"]) then
begin
C := Chr(Ord(C) and not 32); { "a".."я" -> "А".."Я" }
if C in ["А".."Я"] then
iC := Ord(C) - Ord("А");
end
else
iC := 33;
end;
Inc(PV^[iPredC, iC]);
iPredC := iC;
end;
end;
{ вычисление метрики и определение наиболее правдоподобной кодировки }
MinD := 0;
for CP := Low(Vars) to High(Vars) do
begin
PV := @Vars[CP];
PV^[32, 32] := 0;
Max := 1;
for I := 0 to 33 do
for J := 0 to 33 do
if PV^[I, J] > Max then
Max := PV^[I, J];
Factor := 255 / Max; { ноpмализация }
D := 0;
for I := 0 to 33 do
for J := 0 to 33 do
D := D + Abs(PV^[I, J] * Factor - ModelBigrams[I, J]);
if (MinD = 0) or (D < MinD) then
begin
MinD := D;
DetermineRussian := CP;
end;
end;
end;
begin
{ тест: слово "Пример" в разных кодировках (веpоятность ошибок на таких
коpотких текстах высока - в данном слyчае пpосто повезло!) }
writeln(DetermineRussian(#$CF#$F0#$E8#$EC#$E5#$F0, 6) = cpWin1251);
writeln(DetermineRussian(#$8F#$E0#$A8#$AC#$A5#$E0, 6) = cp866);
writeln(DetermineRussian(#$F0#$D2#$C9#$CD#$C5#$D2, 6) = cpKOI8R);
readln;
end.
← →
homm © (2008-01-23 13:25) [2]> --_NextPart_00009A28-00001D02-01C999C0-9345
> Content-Type: text/html
> Content-Transfer-Encoding: 7bitContent-Type: text/html; charset=windows-1251
Content-Transfer-Encoding: quoted-printable
В теле письма заменяем «=» на «=3D»
← →
ZoldBerger (2008-01-23 13:25) [3]либо так:
type
TCode = (win, koi, iso, dos);
const
CodeStrings: array [TCode] of string = ("win","koi","iso","dos");
procedure TForm1.Button1Click(Sender: TObject);
var
str: array [TCode] of string;
norm: array ["А".."я"] of single;
code1, code2: TCode;
min1, min2: TCode;
count: array [char] of integer;
d, min: single;
s, so: string;
chars: array [char] of char;
c: char;
i: integer;
begin
so := Memo1.Text;
norm["А"] := 0.001;
norm["Б"] := 0;
norm["В"] := 0.002;
norm["Г"] := 0;
norm["Д"] := 0.001;
norm["Е"] := 0.001;
norm["Ж"] := 0;
norm["З"] := 0;
norm["И"] := 0.001;
norm["Й"] := 0;
norm["К"] := 0.001;
norm["Л"] := 0;
norm["М"] := 0.001;
norm["Н"] := 0.001;
norm["О"] := 0.001;
norm["П"] := 0.002;
norm["Р"] := 0.002;
norm["С"] := 0.001;
norm["Т"] := 0.001;
norm["У"] := 0;
norm["Ф"] := 0;
norm["Х"] := 0;
norm["Ц"] := 0;
norm["Ч"] := 0.001;
norm["Ш"] := 0.001;
norm["Щ"] := 0;
norm["Ъ"] := 0;
norm["Ы"] := 0;
norm["Ь"] := 0;
norm["Э"] := 0.001;
norm["Ю"] := 0;
norm["Я"] := 0;
norm["а"] := 0.057;
norm["б"] := 0.01;
norm["в"] := 0.031;
norm["г"] := 0.011;
norm["д"] := 0.021;
norm["е"] := 0.067;
norm["ж"] := 0.007;
norm["з"] := 0.013;
norm["и"] := 0.052;
norm["й"] := 0.011;
norm["к"] := 0.023;
norm["л"] := 0.03;
norm["м"] := 0.024;
norm["н"] := 0.043;
norm["о"] := 0.075;
norm["п"] := 0.026;
norm["р"] := 0.038;
norm["с"] := 0.034;
norm["т"] := 0.046;
norm["у"] := 0.016;
norm["ф"] := 0.001;
norm["х"] := 0.006;
norm["ц"] := 0.002;
norm["ч"] := 0.011;
norm["ш"] := 0.004;
norm["щ"] := 0.004;
norm["ъ"] := 0;
norm["ы"] := 0.012;
norm["ь"] := 0.012;
norm["э"] := 0.003;
norm["ю"] := 0.005;
norm["я"] := 0.015;
Str[win] := "АаБбВвГгДдЕеЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮюЯя";
Str[koi] := "юЮаАбБцЦдДеЕфФгГхХиИйЙкКлЛмМнНоОпПяЯрРсСтТуУжЖвВьЬыЫзЗшШэЭщЩчЧъЪ";
Str[iso] := "РрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮюЯяа№бёвђгѓдєеѕжізїијйљкњлћмќн§оўпџ";
Str[dos] := "Ђ ЃЎ‚ўѓЈ"¤…Ґ†¦‡§?Ё‰©ЉЄ‹"ЊЌЋ®ЏЇђа"б"в"г"дoе-ж-зи™йљк›лњмќнћоџпз?и™йљк›лњмќнћоџп";
for c := #0 to #255 do
Chars[c] := c;
min1 := win;
min2 := win;
min := 0;
s := so;
fillchar(count, sizeof(count), 0);
for i := 1 to Length(s) do
inc(count[s[i]]);
for c := "А" to "я" do
min := min + sqr(count[c] / Length(s) - norm[c]);
for code1 := low(TCode) to high(TCode) do
begin
for code2 := low(TCode) to high(TCode) do
begin
if code1 = code2 then
continue;
s := so;
for i := 1 to Length(Str[win]) do
Chars[Str[code2][i]] := Str[code1][i];
for i := 1 to Length(s) do
s[i] := Chars[s[i]];
fillchar(count, sizeof(count), 0);
for i := 1 to Length(s) do
inc(count[s[i]]);
d := 0;
for c := "А" to "я" do
d := d + sqr(count[c] / Length(s) - norm[c]);
if d < min then
begin
min1 := code1;
min2 := code2;
min := d;
end;
end;
end;
s := Memo1.Text;
if min1 <> min2 then
begin
for c := #0 to #255 do
Chars[c] := c;
for i := 1 to Length(Str[win]) do
Chars[Str[min2][i]] := Str[min1][i];
for i := 1 to Length(s) do
s[i] := Chars[s[i]];
end;
Form1.Caption := CodeStrings[min2] + " " + CodeStrings[min1];
Memo2.Text := s;
end;
← →
Игорь Шевченко © (2008-01-23 13:26) [4]homm © (23.01.08 13:25) [2]
С этого момента подробнее и ткнуть носом в доку :)
← →
Рамиль © (2008-01-23 13:27) [5]
> ZoldBerger (23.01.08 13:25) [3]
Он же не клиента пишет, причем тут определение кодировки?
← →
ZoldBerger (2008-01-23 13:28) [6]сор, проглядел =(
← →
homm © (2008-01-23 13:29) [7]> [4] Игорь Шевченко © (23.01.08 13:26)
> С этого момента подробнее и ткнуть носом в доку :)
Тыкать лениво, я просто с рабочего варианта взял :)
Вы же в примере не указываете кодировку нигде. Вот и нужно ее указать для вложеного тела письма. А вообще хороший метод — открываем тело письма, которое везде отображается верно и смотрим, как сделано. Если посылаете только этот текст, без вложений, Ваш вариант можно упростить.
← →
БарЛог © (2008-01-23 13:33) [8]Опасно в год крысы про крысиные хвосты шутить =)
← →
Ega23 © (2008-01-23 13:35) [9]
> ZoldBerger (23.01.08 13:28) [6]
>
> сор, проглядел =(
Ты исходниками займись.
← →
ZoldBerger (2008-01-23 13:40) [10]
> Ega23 © (23.01.08 13:35) [9]
уже давно выложил
← →
Игорь Шевченко © (2008-01-23 13:42) [11]homm © (23.01.08 13:29) [7]
Спасибо, вроде на первый взгляд получилось.
← →
www (2008-01-23 13:50) [12]
> Content-Transfer-Encoding: 8bit
> Date: 17 Jan 2008 17:49:11 +0300
> Status: --_NextPart_00009A28-00001D02-01C999C0-9345
> Content-Type: text/html
> Content-Transfer-Encoding: 7bit
← →
OSokin (2008-01-23 14:01) [13]Сори за оффтоп.
> ZoldBerger (23.01.08 13:40) [10]
Показывай!!!
← →
ketmar © (2008-01-23 15:54) [14][0]:
>Content-Transfer-Encoding: 7bit
это как понимать прикажете? да ни один вменяемый клиент вообще не должен никакого русского показать. ты ж им явно сказал восьмой бит обрезать. просто они кривые, бедняги.
← →
Игорь Шевченко © (2008-01-23 16:17) [15]homm © (23.01.08 13:29) [7]
Победил, большое спасибо.
ketmar © (23.01.08 15:54) [14]
Значит у моих заказчиков невменяемые клиенты. Кысмет.
← →
Amoeba © (2008-01-23 16:20) [16]
> ZoldBerger (23.01.08 13:40) [10]
>
>
> > Ega23 © (23.01.08 13:35) [9]
>
>
> уже давно выложил
>
И где они лежат?
← →
KSergey © (2008-01-23 16:37) [17]> Amoeba © (23.01.08 16:20) [16]
> И где они лежат?
А это место вам всем предлагается поискать :) Он свое дело сделал :) (возможно)
← →
БарЛог © (2008-01-23 16:47) [18]> > И где они лежат?
На сайте Касперского :)
← →
ketmar © (2008-01-23 17:25) [19]>[15] Игорь Шевченко ©(23.01.08 16:17)
а, пардон. я проглядел наличие других секций. извиняюсь.
← →
Anatoly Podgoretsky © (2008-01-23 20:12) [20]> Игорь Шевченко (23.01.2008 13:22:00) [0]
> Content-Transfer-Encoding: 7bit
вот неверный заголовок, у тебя текст 8 битный!
Или укажи 8 бит, или кодируй в base64/qp
Соответственно другие заголовки тоже должны быть поправлены
← →
ketmar © (2008-01-23 22:43) [21]>[20] Anatoly Podgoretsky ©(23.01.08 20:12)
а там есть и 8bit, и base64 части. я тоже на этом прокололся. Игорь просто напихал частей на все случаи жизни. %-)
← →
Игорь Шевченко © (2008-01-23 22:46) [22]ketmar © (23.01.08 22:43) [21]
> Игорь просто напихал частей на все случаи жизни. %-)
Все части нужны и важны, в base64 находится Attach к письму.
а с текстом все хорошо, после совета homm про смену заголовка и замену = на =3D текст письма читается еще двумя почтовыми клиентами :)
← →
ketmar © (2008-01-23 22:55) [23]>[22] Игорь Шевченко ©(23.01.08 22:46)
тогда меняй 7bit на 8bit и пиши багрепорты для всех клиентов, которые забыли обрезать битик. %-)
ксткти:
Content-Type: text/html
на
Content-Type: text/html; charset=windows-1251
ня?
← →
Игорь Шевченко © (2008-01-23 23:03) [24]ketmar © (23.01.08 22:55) [23]
> тогда меняй 7bit на 8bit и пиши багрепорты для всех клиентов,
> которые забыли обрезать битик. %-)
Как ни странно, русский текст показывают все клиенты, которых я пробовал. Но часть из них не распознала тэг meta.
> Content-Type: text/html
> на
> Content-Type: text/html; charset=windows-1251
> ня?
Ну да, собственно, второй вариант и заработал.
← →
homm © (2008-01-23 23:04) [25]> [23] ketmar © (23.01.08 22:55)
> ксткти:
См [2], анимешник хренов :)
← →
ketmar © (2008-01-23 23:06) [26]>[25] homm ©(23.01.08 23:04)
йопт. сорри. это я несколько тормоз, да. %-)
← →
ketmar © (2008-01-23 23:08) [27]>[24] Игорь Шевченко ©(23.01.08 23:03)
>часть из них не распознала тэг meta.
на что имеют полное право. %-) собственно, костыль http-equiv вообще надо было абортировать…
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2008.02.24;
Скачать: [xml.tar.bz2];
Память: 0.55 MB
Время: 0.046 c