উত্তর:
আপনি যদি স্ট্রিংটি সংশোধন করতে পারেন:
// Note: This function returns a pointer to a substring of the original string.
// If the given string was allocated dynamically, the caller must not overwrite
// that pointer with the returned value, since the original pointer must be
// deallocated using the same allocator with which it was allocated. The return
// value must NOT be deallocated using free() etc.
char *trimwhitespace(char *str)
{
char *end;
// Trim leading space
while(isspace((unsigned char)*str)) str++;
if(*str == 0) // All spaces?
return str;
// Trim trailing space
end = str + strlen(str) - 1;
while(end > str && isspace((unsigned char)*end)) end--;
// Write new null terminator character
end[1] = '\0';
return str;
}
আপনি যদি স্ট্রিংটি সংশোধন করতে না পারেন তবে আপনি মূলত একই পদ্ধতিটি ব্যবহার করতে পারেন:
// Stores the trimmed input string into the given output buffer, which must be
// large enough to store the result. If it is too small, the output is
// truncated.
size_t trimwhitespace(char *out, size_t len, const char *str)
{
if(len == 0)
return 0;
const char *end;
size_t out_size;
// Trim leading space
while(isspace((unsigned char)*str)) str++;
if(*str == 0) // All spaces?
{
*out = 0;
return 1;
}
// Trim trailing space
end = str + strlen(str) - 1;
while(end > str && isspace((unsigned char)*end)) end--;
end++;
// Set output size to minimum of trimmed string length and buffer size minus 1
out_size = (end - str) < len-1 ? (end - str) : len-1;
// Copy trimmed string and add null terminator
memcpy(out, str, out_size);
out[out_size] = 0;
return out_size;
}
str
একটি স্থানীয় ভেরিয়েবল, এবং এটি পরিবর্তন করা মূল পয়েন্টারটি পাস করার পরিবর্তিত হয় না C সি তে ফাংশন কলগুলি সর্বদা পাস-বাই-ভ্যালু হয়, কখনও পাস-বাই-রেফারেন্স হয় না।
free()
কার্যকারিতার বৈধ যুক্তি হওয়ার দরকার নেই । একেবারে বিপরীত - দক্ষতার জন্য মেমরি বরাদ্দের প্রয়োজনীয়তা এড়াতে আমি এটি ডিজাইন করেছি। যদি ঠিকানাটিতে পাস করা গতিশীলভাবে বরাদ্দ দেওয়া হয়, তবে কলার সেই স্মৃতিটি মুক্ত করার জন্য এখনও দায়বদ্ধ এবং ফোনকারীকে এখানে ফিরে আসা মানটির সাথে সেই মানটি ওভাররাইট না করার বিষয়ে নিশ্চিত হওয়া দরকার।
isspace
করতে হবে unsigned char
, অন্যথায় আপনি অনির্ধারিত আচরণের ডাক দেন।
এখানে এমন একটি যা আপনার বাফারের প্রথম অবস্থানে স্ট্রিংটি স্থানান্তর করে। আপনি এই আচরণটি পেতে পারেন যাতে আপনি যদি স্ট্রিংটি গতিশীলভাবে বরাদ্দ করেন তবে আপনি এখনও এটি একই পয়েন্টারে মুক্ত করতে পারেন যা ট্রিম () রিটার্ন দেয়:
char *trim(char *str)
{
size_t len = 0;
char *frontp = str;
char *endp = NULL;
if( str == NULL ) { return NULL; }
if( str[0] == '\0' ) { return str; }
len = strlen(str);
endp = str + len;
/* Move the front and back pointers to address the first non-whitespace
* characters from each end.
*/
while( isspace((unsigned char) *frontp) ) { ++frontp; }
if( endp != frontp )
{
while( isspace((unsigned char) *(--endp)) && endp != frontp ) {}
}
if( frontp != str && endp == frontp )
*str = '\0';
else if( str + len - 1 != endp )
*(endp + 1) = '\0';
/* Shift the string so that it starts at str so that if it's dynamically
* allocated, we can still free it on the returned pointer. Note the reuse
* of endp to mean the front of the string buffer now.
*/
endp = str;
if( frontp != str )
{
while( *frontp ) { *endp++ = *frontp++; }
*endp = '\0';
}
return str;
}
সঠিকতার জন্য পরীক্ষা:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* Paste function from above here. */
int main()
{
/* The test prints the following:
[nothing to trim] -> [nothing to trim]
[ trim the front] -> [trim the front]
[trim the back ] -> [trim the back]
[ trim front and back ] -> [trim front and back]
[ trim one char front and back ] -> [trim one char front and back]
[ trim one char front] -> [trim one char front]
[trim one char back ] -> [trim one char back]
[ ] -> []
[ ] -> []
[a] -> [a]
[] -> []
*/
char *sample_strings[] =
{
"nothing to trim",
" trim the front",
"trim the back ",
" trim front and back ",
" trim one char front and back ",
" trim one char front",
"trim one char back ",
" ",
" ",
"a",
"",
NULL
};
char test_buffer[64];
char comparison_buffer[64];
size_t index, compare_pos;
for( index = 0; sample_strings[index] != NULL; ++index )
{
// Fill buffer with known value to verify we do not write past the end of the string.
memset( test_buffer, 0xCC, sizeof(test_buffer) );
strcpy( test_buffer, sample_strings[index] );
memcpy( comparison_buffer, test_buffer, sizeof(comparison_buffer));
printf("[%s] -> [%s]\n", sample_strings[index],
trim(test_buffer));
for( compare_pos = strlen(comparison_buffer);
compare_pos < sizeof(comparison_buffer);
++compare_pos )
{
if( test_buffer[compare_pos] != comparison_buffer[compare_pos] )
{
printf("Unexpected change to buffer @ index %u: %02x (expected %02x)\n",
compare_pos, (unsigned char) test_buffer[compare_pos], (unsigned char) comparison_buffer[compare_pos]);
}
}
}
return 0;
}
উত্স ফাইলটি ছিল trim.c. 'সিসি-ওয়াল ট্রিম.কো-ট্রিম' দিয়ে সংকলিত।
isspace
করতে হবে unsigned char
, অন্যথায় আপনি অনির্ধারিত আচরণের ডাক দেন।
isspace()
তাই কেন " "
এবং এর মধ্যে একটি পার্থক্য থাকবে "\n"
? আমি নিউলাইনগুলির
*(endp + 1) = '\0';
। উত্তরের উদাহরণ পরীক্ষায় 64 এর একটি বাফার ব্যবহার করা হয় যা এই সমস্যাটি এড়ায়।
আমার সমাধান। স্ট্রিং অবশ্যই পরিবর্তনযোগ্য হবে। অন্যান্য সমাধানের কিছুটা উপরে যে সুবিধাটি এটি ফাঁকা স্থানটিকে শুরুতে সরিয়ে দেয় যাতে আপনি পুরানো পয়েন্টারটি ব্যবহার চালিয়ে যেতে পারেন, যদি আপনাকে পরে এটি মুক্ত করতে হয় ()।
void trim(char * s) {
char * p = s;
int l = strlen(p);
while(isspace(p[l - 1])) p[--l] = 0;
while(* p && isspace(* p)) ++p, --l;
memmove(s, p, l + 1);
}
এই সংস্করণটি স্ট্র্যান্ডের পরিবর্তে () পরিবর্তে পরিবর্তিত জায়গায় একটি অনুলিপি তৈরি করে। স্ট্র্যান্ডআপ () এর জন্য _GNU_SOURCE প্রয়োজন, সুতরাং আপনার নিজের নিজস্ব স্ট্র্যান্ডআপ () malloc () এবং strncpy () দিয়ে তৈরি করতে হবে।
char * trim(char * s) {
int l = strlen(s);
while(isspace(s[l - 1])) --l;
while(* s && isspace(* s)) ++s, --l;
return strndup(s, l);
}
trim()
প্রথম কলটি s
হ'ল এবং যদি অগত্যা কোনও আইনী অবস্থানের রেফারেন্স না দেয় তবে ইউবিকে অনুরোধ করুন । ""
isspace()
isspace(p[-1])
p[-1]
isspace
করতে হবে unsigned char
, অন্যথায় আপনি অনির্ধারিত আচরণের ডাক দেন।
if(l==0)return;
শূন্য-দৈর্ঘ্যের
বাম, ডান, উভয়, সমস্ত, জায়গা এবং পৃথক, এবং নির্দিষ্ট বর্ণচিহ্নগুলির একটি সেট (বা ডিফল্টরূপে সাদা স্থান) ছাঁটাই করার জন্য আমার সি মিনি লাইব্রেরিটি এখানে রয়েছে।
#ifndef STRLIB_H_
#define STRLIB_H_ 1
enum strtrim_mode_t {
STRLIB_MODE_ALL = 0,
STRLIB_MODE_RIGHT = 0x01,
STRLIB_MODE_LEFT = 0x02,
STRLIB_MODE_BOTH = 0x03
};
char *strcpytrim(char *d, // destination
char *s, // source
int mode,
char *delim
);
char *strtriml(char *d, char *s);
char *strtrimr(char *d, char *s);
char *strtrim(char *d, char *s);
char *strkill(char *d, char *s);
char *triml(char *s);
char *trimr(char *s);
char *trim(char *s);
char *kill(char *s);
#endif
#include <strlib.h>
char *strcpytrim(char *d, // destination
char *s, // source
int mode,
char *delim
) {
char *o = d; // save orig
char *e = 0; // end space ptr.
char dtab[256] = {0};
if (!s || !d) return 0;
if (!delim) delim = " \t\n\f";
while (*delim)
dtab[*delim++] = 1;
while ( (*d = *s++) != 0 ) {
if (!dtab[0xFF & (unsigned int)*d]) { // Not a match char
e = 0; // Reset end pointer
} else {
if (!e) e = d; // Found first match.
if ( mode == STRLIB_MODE_ALL || ((mode != STRLIB_MODE_RIGHT) && (d == o)) )
continue;
}
d++;
}
if (mode != STRLIB_MODE_LEFT && e) { // for everything but trim_left, delete trailing matches.
*e = 0;
}
return o;
}
// perhaps these could be inlined in strlib.h
char *strtriml(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_LEFT, 0); }
char *strtrimr(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_RIGHT, 0); }
char *strtrim(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_BOTH, 0); }
char *strkill(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_ALL, 0); }
char *triml(char *s) { return strcpytrim(s, s, STRLIB_MODE_LEFT, 0); }
char *trimr(char *s) { return strcpytrim(s, s, STRLIB_MODE_RIGHT, 0); }
char *trim(char *s) { return strcpytrim(s, s, STRLIB_MODE_BOTH, 0); }
char *kill(char *s) { return strcpytrim(s, s, STRLIB_MODE_ALL, 0); }
একটি প্রধান রুটিন এটি সব করে। এটি জায়গায় ট্রিম করে যদি src == dst , অন্যথায়, এটি strcpy
রুটিনগুলির মতো কাজ করে । এটি স্ট্রিং ডিলিমে বর্ণিত অক্ষরের একটি সেটকে ছাঁটাইয়া দেয়, বা শূন্য স্থান শূন্য হলে। এটি বাম, ডান, উভয় এবং সমস্ত (ট্রির মতো) ছাঁটাই করে। এটিতে খুব বেশি কিছু নেই এবং এটি কেবল একবার স্ট্রিংয়ের উপরে পুনরাবৃত্তি করে। কিছু লোকেরা অভিযোগ করতে পারে যে ট্রিমটি ডানদিকে বাম দিকে শুরু হয় তবে যাইহোক, কোনও স্ট্রেনের প্রয়োজন নেই যা যাইহোক বাঁদিকে শুরু হয়। (একটি উপায় বা অন্য উপায় আপনাকে ডান ট্রিমগুলির শেষে স্ট্রিংয়ের শেষে যেতে হবে, যাতে আপনি কাজটি চালিয়ে যাবেন পাশাপাশি আপনিও কাজটি করতে পারেন and) পাইপলাইনিং এবং ক্যাশে আকারগুলি এবং এই জাতীয় বিষয়ে বিতর্ক থাকতে পারে - কে জানে । যেহেতু সমাধানটি বাম থেকে ডানে কাজ করে এবং কেবল একবারে পুনরাবৃত্তি হয়, তাই এটি স্ট্রিমগুলিতেও কাজ করতে প্রসারিত হতে পারে। সীমাবদ্ধতা: এটি ইউনিকোড স্ট্রিংয়ে কাজ করে না ।
dtab[*d]
কাস্ট করে না । স্বাক্ষরিত চর সহ একটি সিস্টেমে এটি পড়বে যা বাগ এবং সম্ভবত ক্রাশের কারণ হবে। *d
unsigned int
dtab[-127]
dtab[*delim++]
কারণ char
সূচীর মানগুলি অবশ্যই castালাই করা উচিত unsigned char
। কোডটি 8-বিট ধরেছে char
। delim
হিসাবে ঘোষণা করা উচিত const char *
। dtab[0xFF & (unsigned int)*d]
হিসাবে পরিষ্কার হবে dtab[(unsigned char)*d]
। কোডটি ইউটিএফ -8 এনকোডযুক্ত স্ট্রিংগুলিতে কাজ করে তবে ASCII নন ব্যবধানের ক্রমগুলি স্ট্রিপ করবে না।
এখানে একটি সহজ, তবুও সঠিক জায়গায় জায়গায় ট্রিম ফাংশনটিতে আমার প্রচেষ্টা।
void trim(char *str)
{
int i;
int begin = 0;
int end = strlen(str) - 1;
while (isspace((unsigned char) str[begin]))
begin++;
while ((end >= begin) && isspace((unsigned char) str[end]))
end--;
// Shift all characters back to the start of the string array.
for (i = begin; i <= end; i++)
str[i - begin] = str[i];
str[i - begin] = '\0'; // Null terminate string.
}
while ((end >= begin) && isspace(str[end]))
U যখন ইউবি প্রতিরোধ করতে পরিবর্তনের পরামর্শ দিন ` str is
. Prevents
isspace
করতে হবে unsigned char
, অন্যথায় আপনি অনির্ধারিত আচরণের ডাক দেন।
<ctype.h>
ইনটগুলির সাথে কাজ করার উদ্দেশ্যে করা হয় যা কোনওটি unsigned char
বা বিশেষ মানকে উপস্থাপন করে EOF
। স্ট্যাকওভারফ্লো . com/q/7131026/225757 দেখুন ।
দেরিতে ট্রিম পার্টিতে
বৈশিষ্ট্যগুলি:
1. অন্যান্য উত্তরের মতো, দ্রুত শুরু ট্রিম করুন।
2. শেষে যাওয়ার পরে, লুপ প্রতি 1 টি পরীক্ষা দিয়ে ডানটি ছাঁটাই। @ Jfm3 এর মতো, তবে সমস্ত সাদা-স্থানের স্ট্রিংয়ের জন্য কাজ করে)
৩. যখন char
স্বাক্ষরিত হয় তখন অপরিজ্ঞাত আচরণ এড়াতে char
কাস্ট *s
করতে পারেন unsigned char
।
চরিত্র পরিচালনা "সকল ক্ষেত্রে যুক্তি হ'ল একটি
int
, যার মান একটি হিসাবে উপস্থাপিত হবেunsigned char
বা ম্যাক্রোর মান সমান হবেEOF
the যুক্তিটির যদি অন্য কোনও মান থাকে তবে আচরণটি অপরিবর্তিত।" সি 11 .7.4 1
#include <ctype.h>
// Return a pointer to the trimmed string
char *string_trim_inplace(char *s) {
while (isspace((unsigned char) *s)) s++;
if (*s) {
char *p = s;
while (*p) p++;
while (isspace((unsigned char) *(--p)));
p[1] = '\0';
}
// If desired, shift the trimmed string
return s;
}
@ chqrlie উপরের মন্তব্য ছাঁটা স্ট্রিং পরিবর্তন না। তাই না....
// Return a pointer to the (shifted) trimmed string
char *string_trim_inplace(char *s) {
char *original = s;
size_t len = 0;
while (isspace((unsigned char) *s)) {
s++;
}
if (*s) {
char *p = s;
while (*p) p++;
while (isspace((unsigned char) *(--p)));
p[1] = '\0';
// len = (size_t) (p - s); // older errant code
len = (size_t) (p - s + 1); // Thanks to @theriver
}
return (s == original) ? s : memmove(original, s, len + 1);
}
এখানে @ অ্যাডাম-রোজেনফিল্ডের ইন-প্লেস পরিবর্তনের রুটিনের মতো একটি সমাধান রয়েছে তবে অকারণে স্ট্রেলেন () এর অবলম্বন ছাড়াই। @Jkramer এর মতো, স্ট্রিংটি বাফারের মধ্যে বাম-সমন্বয়যুক্ত যাতে আপনি একই পয়েন্টারটি মুক্ত করতে পারেন। বড় স্ট্রিংয়ের জন্য অনুকূল নয় কারণ এটি মেমোমোভ ব্যবহার করে না। @ Jfm3 উল্লিখিত ++ / - অপারেটরগুলি অন্তর্ভুক্ত। এফসিটিএক্স- ভিত্তিক ইউনিট পরীক্ষা অন্তর্ভুক্ত।
#include <ctype.h>
void trim(char * const a)
{
char *p = a, *q = a;
while (isspace(*q)) ++q;
while (*q) *p++ = *q++;
*p = '\0';
while (p > a && isspace(*--p)) *p = '\0';
}
/* See http://fctx.wildbearsoftware.com/ */
#include "fct.h"
FCT_BGN()
{
FCT_QTEST_BGN(trim)
{
{ char s[] = ""; trim(s); fct_chk_eq_str("", s); } // Trivial
{ char s[] = " "; trim(s); fct_chk_eq_str("", s); } // Trivial
{ char s[] = "\t"; trim(s); fct_chk_eq_str("", s); } // Trivial
{ char s[] = "a"; trim(s); fct_chk_eq_str("a", s); } // NOP
{ char s[] = "abc"; trim(s); fct_chk_eq_str("abc", s); } // NOP
{ char s[] = " a"; trim(s); fct_chk_eq_str("a", s); } // Leading
{ char s[] = " a c"; trim(s); fct_chk_eq_str("a c", s); } // Leading
{ char s[] = "a "; trim(s); fct_chk_eq_str("a", s); } // Trailing
{ char s[] = "a c "; trim(s); fct_chk_eq_str("a c", s); } // Trailing
{ char s[] = " a "; trim(s); fct_chk_eq_str("a", s); } // Both
{ char s[] = " a c "; trim(s); fct_chk_eq_str("a c", s); } // Both
// Villemoes pointed out an edge case that corrupted memory. Thank you.
// http://stackoverflow.com/questions/122616/#comment23332594_4505533
{
char s[] = "a "; // Buffer with whitespace before s + 2
trim(s + 2); // Trim " " containing only whitespace
fct_chk_eq_str("", s + 2); // Ensure correct result from the trim
fct_chk_eq_str("a ", s); // Ensure preceding buffer not mutated
}
// doukremt suggested I investigate this test case but
// did not indicate the specific behavior that was objectionable.
// http://stackoverflow.com/posts/comments/33571430
{
char s[] = " foobar"; // Shifted across whitespace
trim(s); // Trim
fct_chk_eq_str("foobar", s); // Leading string is correct
// Here is what the algorithm produces:
char r[16] = { 'f', 'o', 'o', 'b', 'a', 'r', '\0', ' ',
' ', 'f', 'o', 'o', 'b', 'a', 'r', '\0'};
fct_chk_eq_int(0, memcmp(s, r, sizeof(s)));
}
}
FCT_QTEST_END();
}
FCT_END();
অন্য একটি, এক লাইনে আসল কাজটি করে:
#include <stdio.h>
int main()
{
const char *target = " haha ";
char buf[256];
sscanf(target, "%s", buf); // Trimming on both sides occurs here
printf("<%s>\n", buf);
}
%n
রূপান্তর নির্দিষ্টকারীর সাহায্যে বাদ দেওয়া অক্ষরের জন্য একটি কাউন্টার দরকার এবং শেষ পর্যন্ত এটি হাতে হাতে করা সহজতর, আমি ভীত।
আমি এই উত্তরগুলির বেশিরভাগটি পছন্দ করি নি কারণ তারা নীচের একটি বা একাধিক করেছেন ...
আমার সংস্করণটি এখানে:
void fnStrTrimInPlace(char *szWrite) {
const char *szWriteOrig = szWrite;
char *szLastSpace = szWrite, *szRead = szWrite;
int bNotSpace;
// SHIFT STRING, STARTING AT FIRST NON-SPACE CHAR, LEFTMOST
while( *szRead != '\0' ) {
bNotSpace = !isspace((unsigned char)(*szRead));
if( (szWrite != szWriteOrig) || bNotSpace ) {
*szWrite = *szRead;
szWrite++;
// TRACK POINTER TO LAST NON-SPACE
if( bNotSpace )
szLastSpace = szWrite;
}
szRead++;
}
// TERMINATE AFTER LAST NON-SPACE (OR BEGINNING IF THERE WAS NO NON-SPACE)
*szLastSpace = '\0';
}
isspace
করতে হবে unsigned char
, অন্যথায় আপনি অনির্ধারিত আচরণের ডাক দেন।
while (isspace((unsigned char) *szWrite)) szWrite++;
যে প্রতিরোধ করবে। কোড সমস্ত পেছনের সাদা স্থান অনুলিপি করে।
*szWrite = *szRead
পয়েন্টার সমান না হলে সম্পাদন করা সেই ক্ষেত্রে লেখাগুলি বাদ দেবে, তবে তারপরে আমরা আরও একটি তুলনা / শাখা যুক্ত করেছি। আধুনিক সিপিইউ / এমএমইউ / বিপি সহ, চেকটি ক্ষতি বা লাভ হবে কিনা তা আমার কোনও ধারণা নেই। সহজ প্রসেসর এবং মেমরি আর্কিটেকচারের সাথে, কেবল অনুলিপি করা এবং তুলনাটি এড়ানো সস্তা।
পার্টিতে খুব দেরি ...
কোনও ব্যাকট্র্যাকিং ছাড়াই সিঙ্গল-পাস ফরোয়ার্ড-স্ক্যানিং সমাধান। উৎস স্ট্রিং প্রতিটি অক্ষর ঠিক পরীক্ষা করা হয় একবার দুইবার। (সুতরাং এটি অন্যান্য সমাধানগুলির বেশিরভাগের চেয়ে দ্রুত হওয়া উচিত, বিশেষত যদি উত্সের স্ট্রিংয়ের অনেকগুলি পিছনের স্থান থাকে))
এর মধ্যে দুটি সমাধান অন্তর্ভুক্ত রয়েছে, একটি উত্সের স্ট্রিংটিকে অন্য গন্তব্য স্ট্রিংয়ের অনুলিপি এবং ছাঁটাই করা এবং অন্যটি উত্সের স্ট্রিংটি জায়গায় ট্রিম করার জন্য। উভয় ফাংশন একই কোড ব্যবহার করে।
(পরিবর্তনযোগ্য) স্ট্রিংটি জায়গায় স্থানান্তরিত করা হয়েছে, সুতরাং এটির মূল পয়েন্টারটি অপরিবর্তিত রয়েছে।
#include <stddef.h>
#include <ctype.h>
char * trim2(char *d, const char *s)
{
// Sanity checks
if (s == NULL || d == NULL)
return NULL;
// Skip leading spaces
const unsigned char * p = (const unsigned char *)s;
while (isspace(*p))
p++;
// Copy the string
unsigned char * dst = (unsigned char *)d; // d and s can be the same
unsigned char * end = dst;
while (*p != '\0')
{
if (!isspace(*dst++ = *p++))
end = dst;
}
// Truncate trailing spaces
*end = '\0';
return d;
}
char * trim(char *s)
{
return trim2(s, s);
}
'\0'
এবং তারপরে পরীক্ষিত isspace()
। এটি দিয়ে সমস্ত চরিত্র পরীক্ষা করা অপব্যয়জনক বলে মনে হচ্ছে isspace()
। স্ট্রিংয়ের শেষে থেকে ব্যাকট্র্যাকিং অ প্যাথলজিকাল ক্ষেত্রে বেশি দক্ষ হওয়া উচিত।
trim()
ঠিক আছে. কর্নার কেস: ওভারল্যাপ এবং trim2(char *d, const char *s)
যখন সমস্যা হয় । d,s
s < d
trim()
আচরণ করা উচিত ? আপনি স্ট্রিং দ্বারা দখল করা মেমরিতে একটি স্ট্রিং ছাঁটাই এবং অনুলিপি করতে বলছেন। বিপরীতে memmove()
, এর জন্য ট্রিম নিজেই করার আগে উত্সের স্ট্রিংয়ের দৈর্ঘ্য নির্ধারণ করা দরকার, যার জন্য অতিরিক্ত স্ট্রিংটি পুরো সময়টিকে স্ক্যান করা প্রয়োজন। একটি ভিন্ন rtrim2()
ফাংশন লেখার চেয়ে ভাল যা উত্সটি পিছনের দিকে গন্তব্যটিতে অনুলিপি করতে জানে এবং সম্ভবত একটি অতিরিক্ত উত্সের স্ট্রিং দৈর্ঘ্যের আর্গুমেন্ট নেয়।
আপনি কী "বেদনাবিহীন" বিবেচনা করছেন তা আমি নিশ্চিত নই।
সি স্ট্রিংগুলি বেশ বেদনাদায়ক। তুচ্ছভাবে আমরা প্রথম অ-সাদা-স্থানের অক্ষরের অবস্থানটি দেখতে পারি:
যখন (isspace (* p)) পি ++;
আমরা দুটি অনুরূপ তুচ্ছ পদক্ষেপের সাথে সর্বশেষ নন-হোয়াইটস্পেসের চরিত্রের অবস্থানটি খুঁজে পেতে পারি:
যখন (* q) q ++; do {q--; } যখন (isspace (* q));
(আমি আপনি ব্যবহার বেদনা আঁচ আছে *
এবং ++
একই সময়ে অপারেটার।)
এখন প্রশ্ন আপনি এই দিয়ে কি করবেন? হাতে থাকা ডেটাটাইপ সত্যিই খুব বড় মজবুত বিমূর্ত নয় String
যা সম্পর্কে ভাবা সহজ, তবে এর পরিবর্তে স্টোরেজ বাইটের অ্যারের চেয়ে সত্যই সবেমাত্র আর কিছু নেই। একটি দৃust় ডেটা প্রকারের অভাব, এমন কোনও ফাংশন লেখা অসম্ভব যা PHperytonby এর chomp
ফাংশনটির মতোই করবে । সি রিটার্নে এ জাতীয় ফাংশন কী হবে?
do { q--; } ...
জানতে আগে একবারের চেক দরকার *q != 0
।
একটি স্ট্রিং গ্রন্থাগার ব্যবহার করুন , উদাহরণস্বরূপ:
Ustr *s1 = USTR1(\7, " 12345 ");
ustr_sc_trim_cstr(&s1, " ");
assert(ustr_cmp_cstr_eq(s1, "12345"));
... যেহেতু আপনি এটি একটি "সাধারণ" সমস্যা, হ্যাঁ আপনাকে একটি # অন্তর্ভুক্ত করা উচিত বা তাই অন্তর্ভুক্ত করা উচিত এবং এটি লিবিসি-তে অন্তর্ভুক্ত নয় তবে এলোমেলো পয়েন্টার এবং আকারের আকার সংরক্ষণ করে আপনার নিজের হ্যাক কাজের উদ্ভাবন করবেন না to বাফার উপচে পড়া
আপনি যদি ব্যবহার করেন glib
তবে আপনি g_strstrip ব্যবহার করতে পারেন
কেবল এই ক্রমবর্ধমান রাখতে, একটি পরিবর্তনীয় স্ট্রিং সহ আরও একটি বিকল্প:
void trimString(char *string)
{
size_t i = 0, j = strlen(string);
while (j > 0 && isspace((unsigned char)string[j - 1])) string[--j] = '\0';
while (isspace((unsigned char)string[i])) i++;
if (i > 0) memmove(string, string + i, j - i + 1);
}
strlen()
size_t
এর পরিসীমা অতিক্রম করতে পারে এমন একটি প্রদান করে int
। সাদা স্থান স্পেস ক্যারেক্টারে সীমাবদ্ধ নয়। শেষ অবধি তবে সবচেয়ে গুরুত্বপূর্ণ: strcpy(string, string + i * sizeof(char));
উত্স এবং গন্তব্য অ্যারে ওভারল্যাপের কারণে অনির্ধারিত আচরণ । memmove()
পরিবর্তে ব্যবহার করুন strcpy()
।
while (isspace((int)string[i])) string[i--] = '\0';
করতে ভুলে গেছি যে স্ট্রিংয়ের শুরুতে লুপ হতে পারে। আপনার এই লুপটি আগের এবং নিম্নলিখিত লাইনগুলির সাথে একত্রিত করা উচিত এবং লিখতে হবেwhile (i > 0 && isspace((unsigned char)string[--i])) { string[i] = '\0'; } size_t end = i;
end
পিছনের নাল বাইটের দিকে ইঙ্গিত করে না এবং আপনার end = ++i;
সাদা অংশের অক্ষরযুক্ত স্ট্রিংগুলির জন্য এখনও সমস্যা ছিল। আমি সবেমাত্র কোডটি ঠিক করেছি।
আমি জানি অনেক উত্তর আছে, তবে আমার সমাধানটি যথেষ্ট ভাল কিনা তা দেখার জন্য আমি এখানে আমার উত্তর পোস্ট করি।
// Trims leading whitespace chars in left `str`, then copy at almost `n - 1` chars
// into the `out` buffer in which copying might stop when the first '\0' occurs,
// and finally append '\0' to the position of the last non-trailing whitespace char.
// Reture the length the trimed string which '\0' is not count in like strlen().
size_t trim(char *out, size_t n, const char *str)
{
// do nothing
if(n == 0) return 0;
// ptr stop at the first non-leading space char
while(isspace(*str)) str++;
if(*str == '\0') {
out[0] = '\0';
return 0;
}
size_t i = 0;
// copy char to out until '\0' or i == n - 1
for(i = 0; i < n - 1 && *str != '\0'; i++){
out[i] = *str++;
}
// deal with the trailing space
while(isspace(out[--i]));
out[++i] = '\0';
return i;
}
isspace(*str)
ইউবি কখন *str < 0
।
size_t n
ভাল, এখনো ইন্টারফেস যখন সম্পর্কে কোন ভাবেই কলার অবহিত না n
সম্পূর্ণ ছাঁটা স্ট্রিং এর জন্য খুবই ছোট হচ্ছে। বিবেচনা করুনtrim(out, 12, "delete data not")
স্ট্রিংয়ে শীর্ষস্থানীয় স্থানগুলি এড়িয়ে যাওয়ার সবচেয়ে সহজ উপায় হ'ল ইমো,
#include <stdio.h>
int main()
{
char *foo=" teststring ";
char *bar;
sscanf(foo,"%s",bar);
printf("String is >%s<\n",bar);
return 0;
}
" foo bar "
।
ঠিক আছে এটি আমার প্রশ্ন। আমি বিশ্বাস করি এটি সর্বাধিক সংক্ষিপ্ত সমাধান যা জায়গায় স্ট্রিং সংশোধন করে ( free
কাজ করবে) এবং কোনও ইউবি এড়িয়ে চলে। ছোট স্ট্রিংয়ের জন্য, এটি সম্ভবত মেমমোভ জড়িত একটি সমাধানের চেয়ে দ্রুত।
void stripWS_LT(char *str)
{
char *a = str, *b = str;
while (isspace((unsigned char)*a)) a++;
while (*b = *a++) b++;
while (b > str && isspace((unsigned char)*--b)) *b = 0;
}
b > str
পরীক্ষা শুধুমাত্র একবার প্রয়োজন হয়। *b = 0;
শুধুমাত্র একবার প্রয়োজন।
#include <ctype.h>
#include <string.h>
char *trim_space(char *in)
{
char *out = NULL;
int len;
if (in) {
len = strlen(in);
while(len && isspace(in[len - 1])) --len;
while(len && *in && isspace(*in)) ++in, --len;
if (len) {
out = strndup(in, len);
}
}
return out;
}
isspace
সমস্ত সাদা স্থান ছাঁটাই করতে সহায়তা করে।
strndup
স্পেস বাদ দিয়ে নতুন স্ট্রিং বাফার তৈরি করতে ব্যবহার করুন ।strndup()
সি স্ট্যান্ডার্ডের অংশ নয় তবে কেবল পিক্সিক্স। তবে এটি কার্যকর করা যেমন সহজ কাজ এটি কোনও বড় বিষয় নয়।
trim_space("")
আয় NULL
। আমি একটি পয়েন্টার আশা করতে চাই ""
। int len;
হওয়া উচিত size_t len;
। isspace(in[len - 1])
ইউবি যখন in[len - 1] < 0
।
while (isspace((unsigned char) *in) in++;
আগে একটি প্রাথমিক প্রাথমিকের len = strlen(in);
চেয়ে পরে আরও দক্ষ হবেwhile(len && *in && isspace(*in)) ++in, --len;
ব্যক্তিগতভাবে, আমি আমার নিজের রোল করব। আপনি স্ট্রটোক ব্যবহার করতে পারেন, তবে আপনাকে এগুলি (বিশেষত যদি আপনি নেতৃস্থানীয় চরিত্রগুলি সরিয়ে থাকেন) সাথে যত্ন নেওয়া দরকার যা আপনি জানেন যে মেমরিটি কী।
পেছনের স্থানগুলি থেকে মুক্তি পাওয়া সহজ এবং বেশ নিরাপদ, কারণ আপনি শেষ স্থানটির শীর্ষে একটি 0 রেখে দিতে পারেন, শেষ থেকে পিছনে গণনা করে। শীর্ষস্থানীয় স্থানগুলি থেকে মুক্তি পাওয়ার অর্থ জিনিসগুলিকে ঘোরানো। আপনি যদি এটি জায়গায় করতে চান (সম্ভবত বোধগম্য) আপনি কোনও অগ্রণী জায়গা না পাওয়া পর্যন্ত সবকিছুকে একটি চরিত্রের পিছনে সরিয়ে রাখতে পারেন। অথবা, আরও দক্ষ হওয়ার জন্য, আপনি প্রথম অ-স্থানের অক্ষরের সূচকটি খুঁজে পেতে পারেন এবং সেই সংখ্যাটি দিয়ে সবকিছু সরিয়ে ফেলতে পারেন। অথবা, আপনি প্রথম অ-স্থানের অক্ষরের জন্য কেবলমাত্র একটি পয়েন্টার ব্যবহার করতে পারেন (তবে তারপরে আপনার যেমন স্ট্রোককের সাথে করা তেমন যত্নবান হওয়া দরকার)।
#include "stdafx.h"
#include "malloc.h"
#include "string.h"
int main(int argc, char* argv[])
{
char *ptr = (char*)malloc(sizeof(char)*30);
strcpy(ptr," Hel lo wo rl d G eo rocks!!! by shahil sucks b i g tim e");
int i = 0, j = 0;
while(ptr[j]!='\0')
{
if(ptr[j] == ' ' )
{
j++;
ptr[i] = ptr[j];
}
else
{
i++;
j++;
ptr[i] = ptr[j];
}
}
printf("\noutput-%s\n",ptr);
return 0;
}
খেলায় কিছুটা দেরি হলেও আমি আমার রুটিনগুলিকে লড়াইয়ে ফেলে দেব। তারা সম্ভবত সবচেয়ে নিখুঁত দক্ষ নয়, তবে আমি বিশ্বাস করি যে তারা সঠিক এবং তারা সহজ ( rtrim()
জটিলতার খামটি চাপ দিয়ে):
#include <ctype.h>
#include <string.h>
/*
Public domain implementations of in-place string trim functions
Michael Burr
michael.burr@nth-element.com
2010
*/
char* ltrim(char* s)
{
char* newstart = s;
while (isspace( *newstart)) {
++newstart;
}
// newstart points to first non-whitespace char (which might be '\0')
memmove( s, newstart, strlen( newstart) + 1); // don't forget to move the '\0' terminator
return s;
}
char* rtrim( char* s)
{
char* end = s + strlen( s);
// find the last non-whitespace character
while ((end != s) && isspace( *(end-1))) {
--end;
}
// at this point either (end == s) and s is either empty or all whitespace
// so it needs to be made empty, or
// end points just past the last non-whitespace character (it might point
// at the '\0' terminator, in which case there's no problem writing
// another there).
*end = '\0';
return s;
}
char* trim( char* s)
{
return rtrim( ltrim( s));
}
char
যুক্তি isspace()
করার (unsigned char)
সম্ভাব্য নেতিবাচক মূল্যবোধের উপর অনির্ধারিত আচরণ এড়ানো। ltrim()
যদি প্রয়োজন না হয় তবে স্ট্রিংটি সরানো এড়িয়ে চলুন ।
এখন পর্যন্ত বেশিরভাগ উত্তর নীচের একটি করে:
strlen()
পুরো স্ট্রিং দিয়ে দ্বিতীয় পাস করে প্রথমে কল করুন ।এই সংস্করণটি কেবল একটি পাস করে এবং ব্যাকট্র্যাক করে না। সুতরাং এটি অন্যের তুলনায় আরও ভাল পারফরম্যান্স করতে পারে, যদিও কেবলমাত্র কয়েকশো চলমান স্থান থাকা (যদি কোনও এসকিউএল কোয়েরি আউটপুট নিয়ে কাজ করার সময় অস্বাভাবিক হয় না) তবে এটি সাধারণ is
static char const WHITESPACE[] = " \t\n\r";
static void get_trim_bounds(char const *s,
char const **firstWord,
char const **trailingSpace)
{
char const *lastWord;
*firstWord = lastWord = s + strspn(s, WHITESPACE);
do
{
*trailingSpace = lastWord + strcspn(lastWord, WHITESPACE);
lastWord = *trailingSpace + strspn(*trailingSpace, WHITESPACE);
}
while (*lastWord != '\0');
}
char *copy_trim(char const *s)
{
char const *firstWord, *trailingSpace;
char *result;
size_t newLength;
get_trim_bounds(s, &firstWord, &trailingSpace);
newLength = trailingSpace - firstWord;
result = malloc(newLength + 1);
memcpy(result, firstWord, newLength);
result[newLength] = '\0';
return result;
}
void inplace_trim(char *s)
{
char const *firstWord, *trailingSpace;
size_t newLength;
get_trim_bounds(s, &firstWord, &trailingSpace);
newLength = trailingSpace - firstWord;
memmove(s, firstWord, newLength);
s[newLength] = '\0';
}
strspn()
এবং strcspn()
একটা সংকুচিত লুপ। এটি খুব অকার্যকর এবং ওভারহেড একক ফরোয়ার্ড পাসের অপ্রমাণিত সুবিধা বামন করবে। strlen()
সাধারণত খুব দক্ষ কোড সহ ইনলাইন প্রসারিত হয়, এটি সত্যিকারের উদ্বেগ নয়। স্ট্রিংয়ের শুরু এবং শেষটি ছাঁটাই করা খুব স্বল্পতার সাথে স্ট্রিংয়ের বিশেষ ক্ষেত্রে খুব কম বা কোনও অ-সাদা অক্ষরের সাথে স্ট্রিংয়ের প্রতিটি অক্ষর সাদা রঙের জন্য পরীক্ষা করার চেয়ে অনেক দ্রুত হবে।
এটি আমি মনে করতে পারি সবচেয়ে সংক্ষিপ্ততম বাস্তবায়ন:
static const char *WhiteSpace=" \n\r\t";
char* trim(char *t)
{
char *e=t+(t!=NULL?strlen(t):0); // *e initially points to end of string
if (t==NULL) return;
do --e; while (strchr(WhiteSpace, *e) && e>=t); // Find last char that is not \r\n\t
*(++e)=0; // Null-terminate
e=t+strspn (t,WhiteSpace); // Find first char that is not \t
return e>t?memmove(t,e,strlen(e)+1):t; // memmove string contents and terminator
}
char *trim(char *s) { char *p = s, *e = s + strlen(s); while (e > s && isspace((unsigned char)e[-1])) { *--e = '\0'; } while (isspace((unsigned char)*p)) { p++; } if (p > s) { memmove(s, p, e + 1 - p); } return s; }
এই ফাংশনগুলি আসল বাফারকে সংশোধন করবে, তাই যদি গতিশীলভাবে বরাদ্দ দেওয়া হয় তবে মূল পয়েন্টারটি মুক্তি দেওয়া যেতে পারে।
#include <string.h>
void rstrip(char *string)
{
int l;
if (!string)
return;
l = strlen(string) - 1;
while (isspace(string[l]) && l >= 0)
string[l--] = 0;
}
void lstrip(char *string)
{
int i, l;
if (!string)
return;
l = strlen(string);
while (isspace(string[(i = 0)]))
while(i++ < l)
string[i-1] = string[i];
}
void strip(char *string)
{
lstrip(string);
rstrip(string);
}
rstrip()
খালি স্ট্রিংয়ে অনির্ধারিত আচরণের আহ্বান জানায়। lstrip()
শ্বেতস্থান অক্ষরের দীর্ঘ প্রাথমিক অংশের সাথে স্ট্রিংয়ে অকারণে ধীর হয়ে যায়। যুক্তিটি isspace()
পাস করা উচিত নয় char
কারণ এটি negativeণাত্মক মানগুলির চেয়ে পৃথক সংজ্ঞায়িত আচরণের আহ্বান করে EOF
।
শিরোনাম Shlwapi.h এ সংজ্ঞায়িত StrTrim ফাংশনটি ব্যবহার সম্পর্কে আপনার কী ধারণা? এটি সরাসরি নিজের পরিবর্তে সংজ্ঞায়িত করা হচ্ছে forward
বিশদটি এখানে পাওয়া যাবে:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773454(v=vs.85).aspx
আপনি যদি
char ausCaptain[]="GeorgeBailey ";
StrTrim(ausCaptain," ");
এই দেব ausCaptain
যেমন "GeorgeBailey"
না "GeorgeBailey "
।
উভয় দিক থেকে আমার স্ট্রিংগুলি ছাঁটাইতে আমি পুরাতনটি ছাড়াও গুডি ব্যবহার করি;) এটি কোনও স্থানের চেয়ে এসকি দিয়ে কম কিছু ছাঁটাই করতে পারে, যার অর্থ নিয়ন্ত্রণের অক্ষরগুলিও ছাঁটাবে!
char *trimAll(char *strData)
{
unsigned int L = strlen(strData);
if(L > 0){ L--; }else{ return strData; }
size_t S = 0, E = L;
while((!(strData[S] > ' ') || !(strData[E] > ' ')) && (S >= 0) && (S <= L) && (E >= 0) && (E <= L))
{
if(strData[S] <= ' '){ S++; }
if(strData[E] <= ' '){ E--; }
}
if(S == 0 && E == L){ return strData; } // Nothing to be done
if((S >= 0) && (S <= L) && (E >= 0) && (E <= L)){
L = E - S + 1;
memmove(strData,&strData[S],L); strData[L] = '\0';
}else{ strData[0] = '\0'; }
return strData;
}
size_t
পরিবর্তে আপনার ব্যবহার করা উচিত unsigned int
। কোডটিতে প্রচুর অনর্থক পরীক্ষা রয়েছে এবং strncpy(strData,&strData[S],L)
উত্স এবং গন্তব্য অ্যারেগুলি ওভারল্যাপ হওয়ার কারণে এটি অনির্ধারিত আচরণের আহ্বান জানায় । memmove()
পরিবর্তে ব্যবহার করুন strncpy()
।
আমি কেবল কোডটিই অন্তর্ভুক্ত করছি কারণ এ পর্যন্ত পোস্ট করা কোডটি সাব-ইস্টিমাল বলে মনে হচ্ছে (এবং আমার কাছে এখনও মন্তব্য করার মতো উত্তর নেই))
void inplace_trim(char* s)
{
int start, end = strlen(s);
for (start = 0; isspace(s[start]); ++start) {}
if (s[start]) {
while (end > 0 && isspace(s[end-1]))
--end;
memmove(s, &s[start], end - start);
}
s[end - start] = '\0';
}
char* copy_trim(const char* s)
{
int start, end;
for (start = 0; isspace(s[start]); ++start) {}
for (end = strlen(s); end > 0 && isspace(s[end-1]); --end) {}
return strndup(s + start, end - start);
}
strndup()
একটি জিএনইউ এক্সটেনশন। আপনার কাছে এটি বা সমতুল্য কিছু না থাকলে নিজের রোল করুন। উদাহরণ স্বরূপ:
r = strdup(s + start);
r[end-start] = '\0';
isspace(0)
মিথ্যা হিসাবে সংজ্ঞায়িত করা হয়, আপনি উভয় ফাংশন সরল করতে পারেন। এছাড়াও ব্লকের memmove()
অভ্যন্তরে সরান if
।
এখানে আমি ডায়ামিক মেমোরি বরাদ্দ ব্যবহার করে ট্রিমসটিআর ফাংশনে ইনপুট স্ট্রিংটি ছাঁটাই করি। প্রথমত, আমরা খুঁজে পাই যে ইনপুট স্ট্রিংয়ে কতগুলি খালি খালি অক্ষর রয়েছে। তারপরে, আমরা সেই আকার এবং নাল টার্মিনেটেড চরিত্রের যত্ন নিয়ে একটি অক্ষর অ্যারে বরাদ্দ করি। যখন আমরা এই ফাংশনটি ব্যবহার করি, আমাদের মূল ফাংশনের ভিতরে মেমরিটি মুক্ত করতে হবে।
#include<stdio.h>
#include<stdlib.h>
char *trimStr(char *str){
char *tmp = str;
printf("input string %s\n",str);
int nc = 0;
while(*tmp!='\0'){
if (*tmp != ' '){
nc++;
}
tmp++;
}
printf("total nonempty characters are %d\n",nc);
char *trim = NULL;
trim = malloc(sizeof(char)*(nc+1));
if (trim == NULL) return NULL;
tmp = str;
int ne = 0;
while(*tmp!='\0'){
if (*tmp != ' '){
trim[ne] = *tmp;
ne++;
}
tmp++;
}
trim[nc] = '\0';
printf("trimmed string is %s\n",trim);
return trim;
}
int main(void){
char str[] = " s ta ck ove r fl o w ";
char *trim = trimStr(str);
if (trim != NULL )free(trim);
return 0;
}
আমি এখানে এটি কিভাবে। এটি স্ট্রিংটিকে স্থানে ছাঁটাই করে দেয়, সুতরাং কোনও ফেরত স্ট্রিংকে বিলোপ করা বা বরাদ্দ স্ট্রিংটিতে পয়েন্টারটি হারাতে কোনও উদ্বেগ নয়। এটি সম্ভব সংক্ষিপ্ত উত্তর নাও হতে পারে তবে এটি বেশিরভাগ পাঠকের কাছে পরিষ্কার হওয়া উচিত।
#include <ctype.h>
#include <string.h>
void trim_str(char *s)
{
const size_t s_len = strlen(s);
int i;
for (i = 0; i < s_len; i++)
{
if (!isspace( (unsigned char) s[i] )) break;
}
if (i == s_len)
{
// s is an empty string or contains only space characters
s[0] = '\0';
}
else
{
// s contains non-space characters
const char *non_space_beginning = s + i;
char *non_space_ending = s + s_len - 1;
while ( isspace( (unsigned char) *non_space_ending ) ) non_space_ending--;
size_t trimmed_s_len = non_space_ending - non_space_beginning + 1;
if (s != non_space_beginning)
{
// Non-space characters exist in the beginning of s
memmove(s, non_space_beginning, trimmed_s_len);
}
s[trimmed_s_len] = '\0';
}
}
char* strtrim(char* const str)
{
if (str != nullptr)
{
char const* begin{ str };
while (std::isspace(*begin))
{
++begin;
}
auto end{ begin };
auto scout{ begin };
while (*scout != '\0')
{
if (!std::isspace(*scout++))
{
end = scout;
}
}
auto /* std::ptrdiff_t */ const length{ end - begin };
if (begin != str)
{
std::memmove(str, begin, length);
}
str[length] = '\0';
}
return str;
}