[JS] fromCharCode zwraca zły znak

0

Witam

Potrzebuje usunąć z inputu nie chciany znak, robię w w ten sposób:

var code = (e.keyCode) ? e.keyCode : e.which;
if (code == options.badCharCode) {
	alert(String.fromCharCode(code));
	text = text.replace(String.fromCharCode(code), text);
	field.val(text);
}

Chcę usunąć przecinek. Sprawdzałem na stronie kodów znaków dla js że jego reprezentacja liczbowa to 188. Niestety alercik wyświetla mi:

<code='html'>
1/4


Pomoże ktoś?

Pozdrawiam
0

oO Nie można po prostu:

text = text.replace(',', text);
0

no właśnie nie, zrobiłem sobie pluginka do jquery i nie chcę inaczej:P

Przecież to powinno działać...:[

0

Po pierwsze, takie coś:

var code = (e.keyCode) ? e.keyCode : e.which;

Możesz zapisać -- dzięki właściwościom operatora || -- w ten zwięźlejszy sposób:

var code = e.keyCode || e.which;

Jeśli chcesz nauczyć się operatorów w JavaScripcie i innych raczej przydatnych rzeczy, polecam książkę "JavaScript - Mocne strony", której autorem jest pracujący dla Yahoo! Douglas Crockford. Książka zwięzła, tania i świetna.

Po drugie to wywalanie przecinków robi się przy pomocy funkcji replace w obiektach typu string -- tak, jak napisał @Demonical Monk. Choć sądząc po Twoim opisie, to jego przykład powiela ten sam błąd, który jest w Twoim kodzie -- nie tyle usuwa przecinek, co zamienia go na wartość zmiennej text (jeśli chcesz usunąć przecinek, to drugim argumentem powinien być pusty string).

Dodam jednak, że jeśli chcesz usunąć ze stringa wszystkie przecinki (tj. więcej niż jeden), to musisz użyć wyrażeń regularnych i opcji g (global), o tak:

var oczyszczonyTekst = tekst.replace(/,/g, '')

Po trzecie, może się zdarzyć, że z jakichś powodów naprawdę będziesz potrzebował wartości liczbowej prostego znaku -- takiego, jaki masz na klawiaturze. Nie szperaj wtedy po tabelach, tylko skorzystaj z funkcji str.charCodeAt(n). Jeśli str to zmienna typu string, to funkcja zwróci wartość liczbową znaku znajdującego się na n-tej pozycji, przy czym znaki liczymy od zera.

Aby sprawdzić, jaki numerek ma przecinek, możesz stworzyć string składający się z jednego znaku (przecinka), a potem sprawdzić, jaki kod ma znak na pierwszym miejscu w tym stringu:

var str = ',';
var kod = str.charCodeAt(0);

Albo zwięźlej, korzystając z potęgi składni JavaScriptu:

var kod = ','.charCodeAt(0);

Szybki test w przeglądarce pokazał mi, że przecinek ma kod nie 188, tylko 44.

Podsumowując, nie jest prawdą, że fromCharCode zwraca zły znak. Ty oczekujesz nie tego znaku, co trzeba (być może tabele, z których korzystasz, są złe). Dodatkowo, jeśli korzystasz z tego do usunięcia przecinków ze stringu, to korzystasz ze złego sposobu.

Przypominam tu nie pierwszy raz jedną z podstawowych zasad pragmatycznego programisty: "Nie, to nie SELECT jest popsute". W Twoim przypadku należałoby to zmienić na "Nie, to nie fromCharCode jest popsute". Błąd bardzo rzadko tkwi w często używanych funkcjach bibliotecznych, czy elementach samego języka (choć JavaScript ma akurat parę takich błędów projektowych, ale są one dobrze znane i udokumentowane). Raczej stawiaj na to że to z Twoim kodem jest coś nie tak.

0

dzięki za tą odpowiedź.
Mój problem nie został jednak rozwiązany. U mnie to 'działa' tylko z 188.

Polecam sprawdzić: http://www.cambiaresearch.com/c4/702b8cd1-e5b0-42e6-83ac-25f0306e3e25/Javascript-Char-Codes-Key-Codes.aspx

0

Jakiś nie bardzo ten twój spis, nie widzę różnicy między kodami JS, a kodami ASCII.
http://www.asciitable.com/asciifull.gif
Z tego wynika że tak jak bswierczynski mówił - przecinek ma kod 44.

0

ok, problem nie leży w samym fromCharCode, tylko w obiekcie event przekazanym do funkcji przy puszczeniu klawisza bibl. jQuery, już tak mnie nie jedźcie(:

Widocznie ten obiekt do identyfikowania wciśniętego znaku nie użwa ascii, tylko tej tabeli w linku.

0

@GhostDog:
Tak jak mówiłem: zawsze traktuj krytycznie swój kod, a dopiero potem np. biblioteki typu jQuery. Możesz wstawić tu link do przykładowej strony z Twoim pluginem, to wtedy będziemy mogli zobaczyć co się dokładnie dzieje. String.replace w JavaScripcie działa, gwarantuję Ci to :D. Co jQuery przekazuje jako argument, to masz w dokumentacji jQuery. Założę się, że dostajesz to, co jest tam napisane.

0

Link potwierdzający moje ostatnie zdanie:

http://api.jquery.com/event.which/

Gdyby użyli ascii mój kod nie byłby taki zły i myślę, że szybszy od takiego który używa regex, itd, ale w takim przypadku nie ma co rozkminać się nad szybkością działania kodu.

0

Możesz wstawić tu link do przykładowej strony z Twoim pluginem, to wtedy będziemy mogli zobaczyć co się dokładnie dzieje.

0

To tylko na localhoście to mam:

plug:

 (function($){  
  $.fn.counter = function(options) {  
   
   var defaults = {  
	resultElementId: '#counter_result',
    maxLength: 50,	
	specialChar: ''
  };  
   var options = $.extend(defaults, options);  
   var counter = 0;   
	
   return this.each(function() {  
			field = $(this);
			field.keyup(function() {
				field = $(this);
				var text = field.val();
				counter = text.length;
				if (counter > options.maxLength) {
					field.val(text.substr(0, options.maxLength));
				}
				
				if (options.specialChar) {
					if (text.indexOf(options.specialChar) >= 0) field.val(text.replace(options.specialChar, ''));
				}
				var charLeft = options.maxLength - counter;
				 (charLeft > 0) ? $(options.resultElementId).text('Pozostało znaków: '+charLeft) : $(options.resultElementId).text('Pozostało znaków: 0');
				

			});
			
			field.focus(function() {
				field = $(this);
				var textLength = field.val().length;
				var charLeft = options.maxLength - textLength;
				(charLeft > 0) ? $(options.resultElementId).text('Pozostało znaków: '+charLeft) : $(options.resultElementId).text('Pozostało znaków: 0');
			});
			
			field.blur(function() {
				$(options.resultElementId).text('');
			});
   });  
  };  
 })(jQuery); 

Kod przykładowej strony

<!DOCTYPE html>
<html>
<head>
	<script type="text/javascript" src="js/jquery.js"></script>
	<script type="text/javascript" src="js/jquery.counter.js"></script>
</head>
<body>
	<input type="text" value=""/>
	<span id="counter_result"></span>

  <p></p>
<script>
$(document).ready(function () {
			$('input').counter({resultElementId: '#counter_result', maxLength: 100, badCharCode: 44});
});
</script>
</body>
0

Oki, i co to ma robić? Co robi plugin, co ma się stać w momencie wciśnięcia przecinka, a co się u Ciebie dzieje?

Jeśli chcesz, by plugin oprócz podawania liczby pozostałych znaków usuwał jeszcze niedozwolone znaki, to chyba lepiej zrobić to po ludzku: dać w opcjach własność invalidChar i użyć zwykłego string.replace. Przy czym należy wywoływać funkcję val tylko w razie potrzeby, tj. gdy string.replace coś zmieni. Można nawet pokusić się o nazwanie opcji invalidChars i usuwanie wszystkich znaków zawierających się w stringu.

I tak, wydajnościowo nie ma to w tym kontekście znaczenia, więc można i należy to olać.

Btw., po co stosujesz takie "sprytne" konstrukcje?

(charLeft > 0) ? $(options.resultElementId).text('Pozostało znaków: '+charLeft) : $(options.resultElementId).text('Pozostało znaków: 0');

Nie wydaje Ci się to sztuczne? Czy może to jakiś idiom, o którym ja nie słyszałem? Ja bym po prostu użył zwykłego if-else, tak by było czytelniejsze.

0

Ma go usunąć z pola, już poprawiłem ten błąd w linii z replace, ale w tej sytuacji nie ma znaczenia.

0

No tak, mogę przekazać znak, i każdorazowo po puszczeniu sprawdzać stringa na jego obecność i tak będę musiał zrobić, chociaż nie chciałem tak robić.

To wszystko pokazało tylko paradoks odmiennego stosowania kodowania znaków.
Ten idiom to po prostu szybszy zapis, masz rację wygląda mniej przejrzyście niż zwykłe if else, ale ja myślę, że nie ma się o co spierać, nie tworzę jakiegoś wielkiego API przecież, tylko mały pomocny pluginek i to że ten mój kod nie jest zbyt czytelny to ja wiem, był pisany na prędkości.

Dzięki za pomoc.

0

@GhostDog:
Ups, już Ci przerobiłem ten plugin, żeby nie było, że nic tylko narzekam i narzekam. Zobacz jak ja to zrobiłem, może nauczysz się jakichś dobrych technik, albo zobaczysz jakieś durne i będziesz mógł się ze mnie pośmiać :-).

Poprawiłem minimalną liczbę rzeczy, normalnie jakbym miał oczyścić kod to zrobiłbym więcej i zacząłbym od formatowania (wcięcia masz jakby różne -- choć może problem pojawił się przy wklejaniu na 4p.net, nie wnikam). Poprawiłem jednak jednego buga: wcześniej źle Ci zliczał liczbę wolnych znaków, gdy ktoś wstawił niewłaściwy znak. Kod powinien wtedy usunąć znak i nie pomniejszać licznika, a ten Twój by pomniejszył (pewnie nie zauważyłeś tego, bo sam kod usuwający nie działał).

Dodałem też ten bajer, że opcja nazywa się invalidChars i można podać jej np. ",.!" -- wtedy usuniętą będą i przecinki, i kropki, i wykrzykniki. Zrobiłem to za pomocą wyrażeń regularnych, choć można było to zrobić inaczej. Wyrażenie regularne tworzę raz, a nie dla każdego elementu, czy przy każdym wywołaniu keyup (zwracam teraz na to uwagę, bo w pewnych rzadkich okolicznościach może Ci to przeszkadzać).

(function($){ 
  $.fn.counter = function(options) { 
   
   var defaults = { 
        resultElementId: '#counter_result',
        maxLength: 50,       
        invalidChars: ''
   };
   var options             = $.extend(defaults, options); 
   var counter             = 0;   
   var escapedInvalidChars = '';
   var invalidCharsRegex   = null;
   if (options.invalidChars) {
     escapedInvalidChars = options.invalidChars.split('').join('\\');
     invalidCharsRegex = new RegExp('[' + escapedInvalidChars + ']', 'g');
   }
   return this.each(function() {
                        field = $(this);
                        field.keyup(function(e) {
                                field = $(this);
                                if (options.invalidChars) {
                                        var cleanVal = field.val().replace(invalidCharsRegex, '');
                                        if (field.val() !== cleanVal) {
                                          field.val(cleanVal);
                                        }
                                }
                                var text = field.val();
                                counter = text.length;
                                if (counter > options.maxLength) {
                                        field.val(text.substr(0, options.maxLength));
                                }
                               
                                var charLeft = options.maxLength - counter;
                                 (charLeft > 0) ? $(options.resultElementId).text('Pozostało znaków: '+charLeft) : $(options.resultElementId).text('Pozostało znaków: 0');
                               

                        });
                       
                        field.focus(function() {
                                field = $(this);
                                var textLength = field.val().length;
                                var charLeft = options.maxLength - textLength;
                                (charLeft > 0) ? $(options.resultElementId).text('Pozostało znaków: '+charLeft) : $(options.resultElementId).text('Pozostało znaków: 0');
                        });
                       
                        field.blur(function() {
                                $(options.resultElementId).text('');
                        });
   });
  }; 
 })(jQuery);

I wywołanie:

$(document).ready(function () {
  $('input').counter({resultElementId: '#counter_result', maxLength: 100, invalidChars: ','});
});

Całość kodu ma pewne -- niezbyt wielkie -- minusy, ale nie będę Ci teraz mącił (zamiast robić replace można zablokować wpisywany znak, ale to się robi zupełnie inaczej).

Co do czytelności kodu, to jest ona praktycznie zawsze bardzo ważna...

0

No dzięki przydatne. ja go przerobiłem na zubożałą wersję z jednym nie chcianym znakiem.
I dobrze zrobiłeś, że w pętli nie robisz Regex bo bym bluzgał;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1