私は、Perlのtr
関数のように、文字列内の文字のセットを別のセットにマップする方法を理解しようとしています。
私は JSとPerlで同等の関数を表示するこのサイト を見つけましたが、残念ながらtrに同等のものはありません。
perlのtr
(文字変換)関数は、文字を1対1にマップするため、
data =~ tr|\-_|+/|;
マップする
- => + and _ => /
JavaScriptでこれを効率的に行うにはどうすればよいですか?
組み込みの同等のものはありませんが、 replace
を使用して、それに近いものを取得できます。
data = data.replace(/[\-_]/g, function (m) {
return {
'-': '+',
'_': '/'
}[m];
});
「効率的」を保証することはできませんが、これは正規表現とコールバックを使用して置換文字を提供します。
function tr( text, search, replace ) {
// Make the search string a regex.
var regex = RegExp( '[' + search + ']', 'g' );
var t = text.replace( regex,
function( chr ) {
// Get the position of the found character in the search string.
var ind = search.indexOf( chr );
// Get the corresponding character from the replace string.
var r = replace.charAt( ind );
return r;
} );
return t;
}
検索文字列と置換文字列が長い場合は、それらをハッシュに入れて、そこから関数を返すことをお勧めします。つまり、tr/abcd/QRST /はハッシュ{a:Q、b:R、c:S、d:T}になり、コールバックはhash [chr]を返します。
方法:
String.prototype.mapReplace = function(map) {
var regex = [];
for(var key in map)
regex.Push(key.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"));
return this.replace(new RegExp(regex.join('|'),"g"),function(Word){
return map[Word];
});
};
完璧な例:
var s = "I think Peak rocks!"
s.mapReplace({"I think":"Actually","rocks":"sucks"})
// console: "Actually Peak sucks!"
これにより、すべてのa
sがb
に、すべてのy
がz
にマッピングされます
var map = { a: 'b', y: 'z' };
var str = 'ayayay';
for (var i = 0; i < str.length; i++)
str[i] = map[str[i]] || str[i];
編集:
どうやらあなたは文字列でそれを行うことはできません。ここに代替があります:
var map = { a: 'b', y: 'z' };
var str = 'ayayay', str2 = [];
for (var i = 0; i < str.length; i++)
str2.Push( map[str[i]] || str[i] );
str2.join('');
この関数は、Perlでの構築方法と似ています。
function s(a, b){ $_ = $_.replace(a, b); }
function tr(a, b){ [...a].map((c, i) => s(new RegExp(c, "g"), b[i])); }
$_ = "Εμπεδοκλης ο Ακραγαντινος";
tr("ΑΒΓΔΕΖΗΘΙΚΛΜΝΟΠΡΣΤΥΦΧΩ", "ABGDEZITIKLMNOPRSTIFHO");
tr("αβγδεζηθικλμνοπρστυφχω", "abgdezitiklmnoprstifho");
s(/Ξ/g, "X"); s(/Ψ/g, "Ps");
s(/ξ/g, "x"); s(/ψ/g, "Ps");
s(/ς/g, "s");
console.log($_);
Perlでは、次のように書くこともできます
tr{-_}{+/}
なので
my %trans = (
'-' => '+',
'_' => '/',
);
my $class = join '', map quotemeta, keys(%trans);
my $re = qr/[$class]/;
s/($re)/$trans{$1}/g;
この後者のバージョンは、JSで問題なく実装できます。
(私のバージョンには、Jonathan Lonowskiのソリューションの重複がありません。)
これは、テキストorig destを受け取り、destの対応する位置にある文字の各文字をテキストで置き換える関数です。
Isは、複数の文字を1つだけで置き換える必要がある場合、またはその逆の場合には十分ではありません。私のユースケースであるポルトガル語のテキストからアクセントを取り除くには不十分です。
function tr(text, orig, dest) {
console.assert(orig.length == dest.length);
const a = orig.split('').map(i=> new RegExp(i, 'g'));
const b = dest.split('');
return a.reduce((prev, curr, idx) => prev.replace(a[idx], b[idx]), text );
}
どうやって使うのですか:
var port = "ÀÂÃÁÉÊÍÓÔÕÜÚÇáàãâêéíóõôúüç";
var ascii = "AAAAEEIOOOUUCaaaaeeiooouuc";
console.log(tr("não têm ações em seqüência", port, ascii)) ;
ジョナサンロノウスキーに似ていますが、単語をサポートし、単一のtr文字だけではありません
"aaabbccddeeDDDffd".replace( /(a|cc|DDD|dd)/g, m => ({'a':'B', 'cc':'DDD', 'DDD':'ZZZ', dd:'QQ'}[m]) )
// RESULT: "BBBbbDDDQQeeZZZffd"
カスタムマップオブジェクトを渡すことができる関数が欲しかったので、 Jonathan Lonowski の答えに基づいて作成しました。特殊文字(正規表現でエスケープする必要がある種類)を置き換える場合は、さらに作業を行う必要があります。
const mapReplace = (str, map) => {
const matchStr = Object.keys(map).join('|');
if (!matchStr) return str;
const regexp = new RegExp(matchStr, 'g');
return str.replace(regexp, match => map[match]);
};
そしてそれは次のように使用されます:
const map = { a: 'A', b: 'B', d: 'D' };
mapReplace('abcde_edcba', map);
// ABcDe_eDcBA