Функция JavaScript для преобразования строки UTF8 между формами полной и половинной ширины

РЕДАКТИРОВАТЬ: Благодаря GOTO 0 теперь я точно знаю, как называется мой вопрос.

Мне нужна функция JavaScript для преобразования из формы полной ширины UTF-8 в форму половинной ширины< /а>.


person xpt    schedule 10.12.2013    source источник
comment
Строки Javascript уже обрабатывают юникод, так какую проблему вы на самом деле пытаетесь решить? Вам действительно нужно самостоятельно обрабатывать двоичные данные в javascript?   -  person jfriend00    schedule 10.12.2013
comment
Это не столько декодирование, сколько отображение. Зачем вообще нужно это делать? Это пахнет проблемой XY.   -  person Matt Ball    schedule 10.12.2013
comment
Как бы вы это ни называли, будь то декодирование или сопоставление, вы можете сказать, что !abc ABC! отличается от !abc ABC!, и эта функция преобразования — это то, о чем я прошу.   -  person xpt    schedule 10.12.2013
comment
Для этого нет простой функции преобразования, и ее создание может быть сложным. Между разными символами Unicode, которые выглядят почти одинаково, например, и a, не всегда существует неотъемлемая связь.   -  person Pekka    schedule 10.12.2013
comment
... но если вы действительно хотите заменить этот конкретный диапазон символов, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ (используйте фактические символы в HTML-файле с кодировкой UTF-8, и все будет в порядке)   -  person Pekka    schedule 10.12.2013
comment
Я не понимаю, почему создание того, что делает - U+FF00 + 0x20 в Javascript, может быть сложным. Для меня это просто в C. PS. Я прошу - U+FF00 + 0x20, а не замену регулярного выражения.   -  person xpt    schedule 10.12.2013
comment
Мой запрос не имеет ничего общего с HTML или файлом HTML. Это чистая реализация функции javascript.   -  person xpt    schedule 10.12.2013
comment
@xpt Вы пробовали мой ответ?   -  person Rezigned    schedule 10.12.2013
comment
Вероятно, эта строка закодирована в UTF16, а не в UTF8 (символы ASCII в UTF8 кодируются точно так же, как обычный ASCII)   -  person VitaliyG    schedule 10.12.2013


Ответы (5)


Попробуй это

function toASCII(chars) {
    var ascii = '';
    for(var i=0, l=chars.length; i<l; i++) {
        var c = chars[i].charCodeAt(0);

        // make sure we only convert half-full width char
        if (c >= 0xFF00 && c <= 0xFFEF) {
           c = 0xFF & (c + 0x20);
        }

        ascii += String.fromCharCode(c);
    }

    return ascii;
}

// example
toASCII("ABC"); // returns 'ABC' 0x41
person Rezigned    schedule 10.12.2013
comment
Спасибо вам Rezigned. Можете ли вы добавить цикл для работы с string, пожалуйста? Я предполагаю, что цикл с вашей функцией все равно будет быстрее, чем замена регулярного выражения. - person xpt; 11.12.2013

Очевидно, вы хотите преобразовать полуширинные и полноширинные символы в их эквивалентные основные латинские формы. Если это правильно, вы можете сделать замену, используя регулярное выражение. Что-то вроде этого должно работать:

var x = "!abc ABC!";
var y = x.replace(
    /[\uff01-\uff5e]/g,
    function(ch) { return String.fromCharCode(ch.charCodeAt(0) - 0xfee0); }
    );

Где x — ваша входная строка, а y — выход.

person GOTO 0    schedule 10.12.2013
comment
благодарю вас. Будет ли это регулярное выражение заменено быстрее, чем цикл for? - person xpt; 11.12.2013
comment
@xpt Это наверняка в моем браузере. Я сделал тестовый jsfiddle здесь: jsfiddle.net/K9b56. Вы также можете изменить входную строку в соответствии с вашими требованиями и посмотреть, как работают оба метода. - person GOTO 0; 11.12.2013
comment
О, большое спасибо за аккуратное решение и доказательство (в 10 раз быстрее, потрясающе). Я считаю, что каждый выбрал бы это решение. Но для себя, в образовательных целях, я выберу Rezigned в качестве ответа. Я хотел бы выбрать более одного ответа. Спасибо еще раз. Я считаю, что другим людям будет полезен ваш ответ. - person xpt; 11.12.2013

2018 год ответ

Спустя много лет — а в интернете до сих пор невозможно найти функцию, которая это делает. Поэтому я написал свой. (Почти выучил японский и корейский, чтобы добраться до этого момента.)

Простая версия

Только латинский диапазон.

var shiftCharCode = Δ => c => String.fromCharCode(c.charCodeAt(0) + Δ);
var toFullWidth = str => str.replace(/[!-~]/g, shiftCharCode(0xFEE0));
var toHalfWidth = str => str.replace(/[!-~]/g, shiftCharCode(-0xFEE0));

Полная версия

Дайте мне знать, если я пропустил какой-либо символ.

(function () {
    let charsets = {
        latin: {halfRE: /[!-~]/g, fullRE: /[!-~]/g, delta: 0xFEE0},
        hangul1: {halfRE: /[ᄀ-ᄒ]/g, fullRE: /[ᆨ-ᇂ]/g, delta: -0xEDF9},
        hangul2: {halfRE: /[ᅡ-ᅵ]/g, fullRE: /[ᅡ-ᅵ]/g, delta: -0xEE61},
        kana: {delta: 0,
            half: "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚", 
            full: "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシ" + 
                "スセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜"},
        extras: {delta: 0,
            half: "¢£¬¯¦¥₩\u0020|←↑→↓■°", 
            full: "¢£¬ ̄¦¥₩\u3000│←↑→↓■○"}
    };
    let toFull = set => c => set.delta ? 
        String.fromCharCode(c.charCodeAt(0) + set.delta) : 
        [...set.full][[...set.half].indexOf(c)];
    let toHalf = set => c => set.delta ? 
        String.fromCharCode(c.charCodeAt(0) - set.delta) : 
        [...set.half][[...set.full].indexOf(c)];
    let re = (set, way) => set[way + "RE"] || new RegExp("[" + set[way] + "]", "g");
    let sets = Object.keys(charsets).map(i => charsets[i]);
    window.toFullWidth = str0 => 
        sets.reduce((str,set) => str.replace(re(set, "half"), toFull(set)), str0);
    window.toHalfWidth = str0 => 
        sets.reduce((str,set) => str.replace(re(set, "full"), toHalf(set)), str0);
})();

/* Example starts here: */
var set = prompt("Enter a couple of comma-separated strings (half or full-width):", 
    ["aouäöü123", "'\"?:", "¢£¥₩↑→", "コンニチハ", "ᄀ까ᅢ"].join()).split(",");
var steps = [set, set.map(toFullWidth), set.map(toFullWidth).map(toHalfWidth)];
var tdHTML = str => `<td>${str}</td>`;
var stepsHTML = steps.map(step => step.map(tdHTML).join(""));
var rows = document.getElementsByTagName("tr");
[...rows].forEach((row,i) => row.insertAdjacentHTML("beforeEnd", stepsHTML[i]));
th, td {border: 1px solid lightgrey; padding: 0.2em;}
th {text-align: left;}
table {border-collapse: collapse;}
<table>
    <tr><th scope="row">Input:</th></tr>
    <tr><th scope="row">Full-width:</th></tr>
    <tr><th scope="row">Half-width:</th></tr>
</table>

person 7vujy0f0hy    schedule 24.12.2017
comment
Тем временем я обнаружил, что карты хангыль в моем коде ошибочны из-за некоторых пробелов в Unicode (сломанное отображение 1: 1). Подождите, пока я их не исправлю (не сегодня) или исправлю сами. Или просто полностью удалите записи hangul1 и hangul2 в качестве временной меры. - person 7vujy0f0hy; 29.12.2017

Ответ GOTO 0 очень полезен, но мне также нужно преобразовать пробел из полной ширины в половину ширины .

Итак, ниже мой код:

const halfwidthValue = value
      .replace(/[\uff01-\uff5e]/g, fullwidthChar => String.fromCharCode(fullwidthChar.charCodeAt(0) - 0xfee0))
      .replace(/\u3000/g, '\u0020');
person Peter Chen    schedule 23.10.2019

Данные решения не работают для всех случаев преобразования Каны из полной ширины в половинную (например, デジタル не преобразуется должным образом). Я сделал функцию для преобразования Zenkaku в Hankaku Katakana, надеюсь, это поможет.

function convertToHalfWidth(string) {
  let characters = getCharacters(string);
  let halfWidthString = ''
  characters.forEach(character => {
    halfWidthString += mapToHankaku(character);
  });
  return halfWidthString;
}

function getCharacters(string) {
   return string.split("");
}

function mapToHankaku(character) {
  let zenHanMap = getZenkakuToHankakuMap();
  if (typeof zenHanMap[character] === 'undefined') {
    return character;
  } else {
    return zenHanMap[character];
  }
}

function getZenkakuToHankakuMap() {
  let zenHanMap = {
    'ァ': 'ァ',
    'ア': 'ア',
    'ィ': 'ィ',
    'イ': 'イ',
    'ゥ': 'ゥ',
    'ウ': 'ウ',
    'ェ': 'ェ',
    'エ': 'エ',
    'ォ': 'ォ',
    'オ': 'オ',
    'カ': 'カ',
    'ガ': 'ガ',
    'キ': 'キ',
    'ギ': 'ギ',
    'ク': 'ク',
    'グ': 'グ',
    'ケ': 'ケ',
    'ゲ': 'ゲ',
    'コ': 'コ',
    'ゴ': 'ゴ',
    'サ': 'サ',
    'ザ': 'ザ',
    'シ': 'シ',
    'ジ': 'ジ',
    'ス': 'ス',
    'ズ': 'ズ',
    'セ': 'セ',
    'ゼ': 'ゼ',
    'ソ': 'ソ',
    'ゾ': 'ゾ',
    'タ': 'タ',
    'ダ': 'ダ',
    'チ': 'チ',
    'ヂ': 'ヂ',
    'ッ': 'ッ',
    'ツ': 'ツ',
    'ヅ': 'ヅ',
    'テ': 'テ',
    'デ': 'デ',
    'ト': 'ト',
    'ド': 'ド',
    'ナ': 'ナ',
    'ニ': 'ニ',
    'ヌ': 'ヌ',
    'ネ': 'ネ',
    'ノ': 'ノ',
    'ハ': 'ハ',
    'バ': 'バ',
    'パ': 'パ',
    'ヒ': 'ヒ',
    'ビ': 'ビ',
    'ピ': 'ピ',
    'フ': 'フ',
    'ブ': 'ブ',
    'プ': 'プ',
    'ヘ': 'ヘ',
    'ベ': 'ベ',
    'ペ': 'ペ',
    'ホ': 'ホ',
    'ボ': 'ボ',
    'ポ': 'ポ',
    'マ': 'マ',
    'ミ': 'ミ',
    'ム': 'ム',
    'メ': 'メ',
    'モ': 'モ',
    'ャ': 'ャ',
    'ヤ': 'ヤ',
    'ュ': 'ュ',
    'ユ': 'ユ',
    'ョ': 'ョ',
    'ヨ': 'ヨ',
    'ラ': 'ラ',
    'リ': 'リ',
    'ル': 'ル',
    'レ': 'レ',
    'ロ': 'ロ',
    'ヮ': '',
    'ワ': 'ワ',
    // 'ヰ': '゙  ゚',
    // 'ヱ': '',
    'ヲ': 'ヲ',
    'ン': 'ン',
    'ヴ': 'ヴ',
    // 'ヵ': '',
    // 'ヶ': '',
    // 'ヷ': '',
    // 'ヸ': '',
    // 'ヹ': '',
    // 'ヺ': '',
    '・': '・',
    'ー': 'ー',
    // 'ヽ': '',
    // 'ヾ': '',
    // 'ヿ': '',
  };
  return zenHanMap;
}

Используйте следующим образом convertToHalfWidth('デジタル');

Вы можете передать результат этой функции функции, упомянутой GOTO 0, и получить полный результат половинной ширины для японского языка.

Ссылка: https://en.wikipedia.org/wiki/Katakana#Unicode

person Lav Shinde    schedule 13.02.2019